Java 8 インターフェイスにはデフォルトのメソッドがある可能性があるためです。実装メソッドからメソッドを明示的に呼び出す方法を知っています。つまり、Java でデフォルト メソッドを明示的に呼び出す方法を参照してください。
しかし、たとえばプロキシでリフレクションを使用してデフォルト メソッドを明示的に呼び出すにはどうすればよいでしょうか。
例:
interface ExampleMixin {
String getText();
default void printInfo(){
System.out.println(getText());
}
}
class Example {
public static void main(String... args) throws Exception {
Object target = new Object();
Map<String, BiFunction<Object, Object[], Object>> behavior = new HashMap<>();
ExampleMixin dynamic =
(ExampleMixin) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),new Class[]{ExampleMixin.class}, (Object proxy, Method method, Object[] arguments) -> {
//custom mixin behavior
if(behavior.containsKey(method.getName())) {
return behavior.get(method.getName()).apply(target, arguments);
//default mixin behavior
} else if (method.isDefault()) {
//this block throws java.lang.IllegalAccessException: no private access for invokespecial
return MethodHandles.lookup()
.in(method.getDeclaringClass())
.unreflectSpecial(method, method.getDeclaringClass())
.bindTo(target)
.invokeWithArguments();
//no mixin behavior
} else if (ExampleMixin.class == method.getDeclaringClass()) {
throw new UnsupportedOperationException(method.getName() + " is not supported");
//base class behavior
} else{
return method.invoke(target, arguments);
}
});
//define behavior for abstract method getText()
behavior.put("getText", (o, a) -> o.toString() + " myText");
System.out.println(dynamic.getClass());
System.out.println(dynamic.toString());
System.out.println(dynamic.getText());
//print info should by default implementation
dynamic.printInfo();
}
}
編集: How do I invoke Java 8 default methods refletivelyで同様の質問がされていることは知っていますが、これは2つの理由で私の問題を解決していません:
- その質問で説明されている問題は、一般的にリフレクションを介して呼び出す方法を目的としているため、デフォルトのメソッドとオーバーライドされたメソッドの区別はありませんでした。これは簡単で、インスタンスのみが必要です。
- 答えの1つ-メソッドハンドルを使用-は、アクセス修飾子をルックアップクラスのフィールドに変更するなどの厄介なハック(imho)でのみ機能します。これは、次のような「ソリューション」の同じカテゴリです: Javaリフレクションを使用してプライベート静的最終フィールドを変更します:それが可能であることを知っているのは良いことですが、私はそれを本番環境では使用しません.それを行うための「公式」の方法を探しています.
IllegalAccessException
が投げ込まれるunreflectSpecial
Caused by: java.lang.IllegalAccessException: no private access for invokespecial: interface example.ExampleMixin, from example.ExampleMixin/package
at java.lang.invoke.MemberName.makeAccessException(MemberName.java:852)
at java.lang.invoke.MethodHandles$Lookup.checkSpecialCaller(MethodHandles.java:1568)
at java.lang.invoke.MethodHandles$Lookup.unreflectSpecial(MethodHandles.java:1227)
at example.Example.lambda$main$0(Example.java:30)
at example.Example$$Lambda$1/1342443276.invoke(Unknown Source)