Differences between BeanInfo:methodDescriptors and class:declaredMethods : multiple methods with same name and method masking
When trying to get JPA annotations at runtime for some properties, I encountered this problem. I can't explain why.
PS: after a debugging session with Spring, I found the explanation of this problem: bridged methods that are introduced at compile time by the compiler. Please see my own answer to this question..
Here is a sample source code replicating the issue (simplified version of real code).
import java.beans.BeanInfo; import java.beans.Introsp开发者_开发技巧ectionException; import java.beans.Introspector; import java.beans.MethodDescriptor; import java.io.Serializable; import java.lang.reflect.Method;
public class MethodMasking {
public interface HasId<ID extends Serializable> {
void setId(ID id);
ID getId();
}
public interface Storeable extends HasId<Long> {}
class Item implements Storeable {Long id; String code;
Item(Long id, String code) { this.id = id; this.code = code; }
public Long getId() { return id; }
public void setId(Long id) {this.id = id;}
}
public static void main(String[] args) throws IntrospectionException {
final BeanInfo beanInfo = Introspector.getBeanInfo(Item.class);
java.lang.System.out.println("BeanInfo:methodDescriptors:");
final MethodDescriptor[] methodDescriptors = beanInfo.getMethodDescriptors();
for (MethodDescriptor methodDescriptor : methodDescriptors) {
java.lang.System.out.println("\t"+methodDescriptor.getMethod().getName());
}
java.lang.System.out.println("class:declaredMethods:");
final Method[] declaredMethods = Item.class.getDeclaredMethods();
for (Method declaredMethod : declaredMethods) {
java.lang.System.out.println("\t"+declaredMethod.getName());
}
}
} Output of the program:
BeanInfo:methodDescriptors:
hashCode
wait
getId
notifyAll
equals
wait
wait
toString
setId
notify
setId
getClass
class:declaredMethods:
getId
getId
setId
setId
Now I'm confused:
why in beanInfo there are 2 methods descriptors for setId but only one for getId ? why in declared method there are 2 methods for getId and 2 methods for setId ?While debugging I have these methods signatures when using the getDeclaredMethods :
[0] = {java.lang.reflect.Method@139}"public java.lang.Long MethodMasking$Item.getId()"
[1] = {java.lang.reflect.Method@446}"public java.io.Serializable MethodMasking$Item.getId()"
[2] = {java.lang.reflect.Method@447}"public void MethodMasking$Item.setId(java.lang.Long)"
[3] = {java.lang.reflect.Method@448}"public void MethodMasking$Item.setId(java.io.Serializable)"
Edit: After some tests I have found that the cause of the problem is the usage of generics in the HasId interface...
Declared this way, the problem disapear: no more duplicate methods.
public interface HasId {
void setId(Long id);
Long getId();
}
public interface Storeable extends HasId {}
It is because the compiler is introducing bridge methods when Generics are used:
some explanation here
Print out more information about the methods your receive : not only their names but param lists. Try to have enough information to distinguish overrides and averloads. The difference can come from this but it's still not clear for me.
Regards, Stéphane
精彩评论