Wiem, że jest sobie taki interfejs:
com.xxx.Listener{
void eventHandlerA();
void eventHandlerB();
}
którego implementacja jest używana przez bliżej nieznaną klasę:
com.yyy.BaseClass{
addXXXListener(com.xxx.Listener listener);
removeXXXListener(com.xxx.Listener listener);
//...
}
Jest też sobie klasa com.zzz.DerivedClass extends BaseClass {/*...*/}
, do obiektu której mam faktyczny dostęp.
Do żadnego źródła tych klas, ani interfejsów nie mam dostępu. Wszystko co jest mi znane, to z dokumentacji i wyciągania przez RTTI.
Potrzebuję wywoływać metody addXXXListener
i removeXXXListener
, ale problem jest z argumentem. Nie mogę jawnie użyć obiektu implementującego com.xxx.Listener
. Jednak muszę mieć obiekt, który będzie ten interfejs implementował.
Na razie wykombinowałem coś takiego co faktycznie działa:
@SuppressWarnings("MarkerInterface")
private interface ProxyListener extends com.xxx.Listener {} //tu leci warning
ProxyListener proxyListener = new ProxyListener(){
@Override void eventHandlerA() {/*...*/}
@Override void eventHandlerB() {/*...*/}
}
Ale nadal kompilator irytuje mnie tym jednym pozostałym ostrzeżeniem o tym, że próbuję wrednie użyć prywatnego API. :)
Próbowałem kombinować z dynamic proxy i definicją własnego InvocationHandler'a, ale wszystkie przykłady użycia które widziałem zawsze gdzieś jawnie wymuszają użycie w kodzie com.xxx.Listener
. A ja szukam sposobu aby nazwa tego interfejsu była zapisana najlepiej w jakimś stringu, a nie w kodzie, no i oczywiście aby uzyskać obiekt, który będzie mógł zostać łyknięty przez metody wywoływane też przez refleksję z DerivedClass
.
Wywołuję (w uproszczeniu) w taki sposób:
private final Method addYYYListener = getMethod(getDerivedClassObject(),
"addXXXListener", "com.xxx.Listener");
private final Method removeYYYListener = getMethod(getDerivedClassObject(),
"removeXXXListener", "com.xxx.Listener"),
//...
if(!addYYYListener.isAccessible())
addYYYListener.setAccessible(true);
addYYYListener.invoke(getDerivedClassObject(), proxyListener);
//...
if(!removeYYYListener.isAccessible())
removeYYYListener.setAccessible(true);
removeYYYListener.invoke(getDerivedClassObject(), proxyListener);
Wszystko mi działa, ale jednak chciałbym wyeliminować z proxyListener użycie interfejsu com.xxx.Listener
, a jednocześnie mieć ten kontrolowany przez siebie obiekt, który go implementuje.
Takie mam zboczenie, że zawsze piszę kod "0 warnings", a ten jeden którego nie da się nawet wyłączyć (no i nie powinno) trochę mnie męczy...
Poza tym w niektórych przypadkach nie będę mógł użyć tego myku z dziedziczeniem po interfejsie takim jak com.xxx.Listener
bo prawdopodobnie nie będzie on dostępny.
Jakieś pomysły?
ps. Gdyby ktoś chciał mnie przekonywać, żebym to olał, to niech sobie daruje. Problem nie dotyczy tylko jednego przypadku bo to tylko pierwszy z wielu.