最もクリーンな解決策は、共通機能を定義するinterface
を使用することです。もちろん
public interface Controller {
void index(RoutingContext routingContext);
}
public class PostsController implements Controller {
@Route(method="get", path = "/")
public void index(RoutingContext routingContext){
routingContext.response()
.putHeader("content-type", "application/json; charset=utf-8")
.end(Json.encodePrettily("{}"));
}
}
Class<? extends Controller> controllerType =
Class.forName("some.package"+controllers.getString(i))
.asSubclass(Controller.class);
Controller controller=controllerType.newInstance();
Handler<RoutingContext> h=controller::index;
、これは注釈ベースの処理と相互作用しません。ダイナミックな解決策は、これはあなたが指定されていませんでしたあなたのHandler
インタフェースに関する特定の仮定の下で動作します
Class<?> controllerType = Class.forName("some.package"+controllers.getString(i));
MethodHandles.Lookup lookup=MethodHandles.lookup();
Method[] methods = controllerType.getMethods();
Object instance = null;
for (Method m : methods) {
Route annotation = m.getAnnotation(Route.class);
if (annotation != null) {
if(instance == null) instance = controllerType.newInstance();
Handler<RoutingContext> handler
=createHandler(lookup, instance, m, RoutingContext.class);
router.get(annotation.path()).handler(handler);
}
}
static <T> Handler<T> createHandler(MethodHandles.Lookup lookup,
Object instance, Method m, Class<T> arg) throws Throwable {
MethodHandle mh=lookup.unreflect(m);
MethodType t=mh.type();
Class<?> receiver=t.parameterType(0);
if(t.parameterCount()!=2
|| !receiver.isAssignableFrom(instance.getClass())
|| !t.parameterType(1).isAssignableFrom(arg))
throw new IllegalArgumentException(m+" not suitable for Handler<"+arg.getName()+'>');
t=t.dropParameterTypes(0, 1);
return (Handler)LambdaMetafactory.metafactory(lookup, "accept",
MethodType.methodType(Handler.class, receiver),
t.changeParameterType(0, Object.class), mh, t)
.getTarget().invoke(instance);
}
ようになります。 interface Handler<T> extends Consumer<T> {}
のように定義されていれば、それはそのままで動作します。それ以外の場合は、機能インタフェースの関数メソッドの実際の名前に"accept"
を適合させる必要があります。また、型パラメータにバウンドがある場合は、t.changeParameterType(0, Object.class)
行を実際のバウンド(型消去後のHandler
のパラメータ型)を使用するように変更する必要があります。
一般的に、これはすぐにエラーフィードバックがないので、非常に注意が必要です。最悪の場合、エラーはコールバックが実際に呼び出されたときにのみ検出されます(特定の引数で)。
原則として
、あなたもちょうどすなわち
Handler<RoutingContext> handler=rc -> { try {
m.invoke(capturedInstance, rc);
} catch(ReflectiveOperationException ex) { ex.printStackTrace(); }};
、メソッドの反射呼び出しをカプセル化するラムダ式を作成することもできますが、これはあなたが非常に遅く、エラーを検出されるという事実は変わりません...
すべてのコントローラにこの 'index'メソッドがあることを保証する必要はありませんか?あなたのコントローラがインデックスメソッドを必要とするいくつかのインタフェースを拡張するようにして、それを解決してください。 – ifly6
インデックス関数はそれらになりますが、カスタム関数もいくつかあります。なぜそれを動的にしたいのですか? –
はい、カスタム関数はすべて、そのファイルがインターフェイスを実装している限り、ファイル内で宣言できます。ただし、JVMは、ファイルにそのメソッドがあることを保証できるかどうかはわかりません。すべてのコントローラーに共通のインターフェースを実装させることで、これを保証することができます。 – ifly6