Poiché le interfacce Java 8 potrebbero avere metodi predefiniti. So come richiamare il metodo in modo esplicito dal metodo di applicazione, vale a dire (vedi Explicitly calling a default method in Java)Come richiamare esplicitamente il metodo predefinito da un proxy dinamico?
Ma come faccio a esplicitamente invoco il metodo predefinito utilizzando la riflessione, per esempio su un proxy?
Esempio:
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();
}
}
Edit: So che una domanda simile è stato chiesto in How do I invoke Java 8 default methods refletively, ma questo non ha risolto il mio problema per due motivi:
- il problema descritto in quella domanda mirava a come richiamarlo tramite la riflessione in generale - quindi nessuna distinzione tra È stato eseguito il metodo efault e overriden - e questo è semplice, hai solo bisogno di un'istanza.
- una delle risposte - utilizzando il metodo handle - funziona solo con brutto hack (imho) come modificare i modificatori di accesso ai campi della classe di ricerca, che è la stessa categoria di "soluzioni" come questa: Change private static final field using Java reflection: è buono per so che è possibile, ma non lo userei in produzione - Sto cercando un modo "ufficiale" per farlo.
Il IllegalAccessException
è gettato in 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)
non è un duplicato di questo http://stackoverflow.com/questions/22614746/how-do-i-invoke-java-8-default-methods-refletively –
"* sto cercando per un modo "ufficiale" di farlo * "Potrei sbagliarmi, ma temo che ufficialmente non si debba essere in grado di invocare il metodo da supertipo se il sottotipo lo ha sovrascritto. Diciamo che il tuo supertipo ha il metodo 'acceptSquare' che può accettare qualsiasi Quadrato, ma il tuo sottotipo è * specializzato * nella gestione dei soli quadrati rossi, quindi lo sostituisce di conseguenza per aggiungere un test per il colore (dopodiché richiama' super.addSquare'). Quindi permettere a qualcuno di invocare dall'esterno l'implementazione da supertipo (anche tramite riflessione) di tale metodo potrebbe essere un grosso buco di sicurezza. – Pshemo
Che ne dici di mixin - l'aggiunta di funzionalità a una classe esistente utilizzando un proxy dinamico? Ad esempio, ho un'istanza e voglio aggiungere funzionalità aggiuntive "aggiungendo" interfacce con metodi predefiniti all'istanza in fase di runtime. Deve esserci un modo –