I have the following setup
class A {
@Override
public String toString(){
return "A's toString";
}
}
class B extends A {
@Override
public String toString(){
return "B's toString";
}
}
I have an instance of class B and I'd like to call B.super.toString ONLY using reflection. Note that class A and B are not specific, I am working with objects which can be other than A or B but the method I'm looking for is surely in the class. I have tried the followings without any success:
1:
...
private void callSuperToString(Object object){
//class B is an example for object.getClass in this example
String value = (String) object.getClass()
.getSuperclass()
.getMethod("toString")
.invoke(object.getClass().getSuperclass().newInstance());
}
In the case above the value will be "A's toString" which is what I expect, however this is not good for me as this requires an instantiation of the super class which is not always possible (e.g the super class is abstract) moreover the new instance' fields are not identical to the object's super class's field. Not a solution for me.
2:
...
private void callSuperToString(Object object){
Method method = object.getClass().superClass().getDeclaredMethod("toString");
String value = (String) method.invoke(object);
}
In this case value will be "B's toString" which is not as the expected "A's toString". Is it possible to achieve what I'm trying to do here?
EDIT:
3
...
private void callSuperToString(Object object){
MethodHandle handle = MethodHandles.lookup()
.findSpecial(object.getClass().getSuperclass(), "toString",
MethodType.methodType(String.class),
object.getClass());
value= (String) handle.invoke(object);
}
The following throws this exception: java.lang.IllegalAccessException: no private access for invokespecial
EDIT 2:
Yes this might be a duplicate. I found the answer in the link provided which was not the accepted answer. The following works perfectly:
Solution:
...
private void callSuperToString(Object object){
Field IMPL_LOOKUP = MethodHandles.Lookup.class.getDeclaredField("IMPL_LOOKUP");
IMPL_LOOKUP.setAccessible(true);
MethodHandles.Lookup lkp = (MethodHandles.Lookup) IMPL_LOOKUP.get(null);
MethodHandle h1 = lkp.findSpecial(object.getClass().getSuperclass(), "toString",
MethodType.methodType(String.class),
object.getClass());
value= (String) h1.invoke(object);
}