I have a generic java interface Id<T> with a single method T getId() and a class MyClass that implements Id<Long>. When I inspect the methods declared on MyClass using java reflection, I see two methods: one with return type Long, and one with return type Object. Where does the second method come from and how can I remove it?
Here is the source:
package mypackage;
import java.lang.reflect.Method;
public class MainClass {
    public static void main(String[] args) {
        for (Method method : MyClass.class.getDeclaredMethods()) {
            System.out.println(method);
        }
        // prints out two lines
        // public java.lang.Long mypackage.MyClass.getId()   <-- ok
        // public java.lang.Object mypackage.MyClass.getId() <-- not ok
    }
}
interface Id<T> {
    T getId();
}
class MyClass implements Id<Long> {
    @Override
    public Long getId() {
        return new Long(0);
    };
}
                The second method is a synthetic bridge method, you can check it with method.isSynthetic() or method.isBridge(). You can't remove it, but if you don't want to see it in the list of declared methods, just check all those methods to have isBridge() == false.
Synthetic bridge methods are added automatically to generic classes during compilation. You can read more about synthetic methods here.
for (Method method : MyClass.class.getDeclaredMethods()) {
    System.out.println("Method: " + method);
    System.out.println("synthetic: " + method.isSynthetic());
    System.out.println("bridge: " + method.isBridge());
}
// 1
//Method: public java.lang.Long Main$MyClass.getId()
//synthetic: false
//bridge: false
// 2
//Method: public java.lang.Object Main$MyClass.getId()
//synthetic: true
//bridge: true
                        This is feature. Same issue was raised in
JDK-8060179 Class.getDeclaredMethods() returning inconsistent results with generics and closed as 'not a bug'.
You can find the compiled methods by javap -c MyClass:
Compiled from "Test.java"
class MyClass implements Id<java.lang.Long> {
  MyClass();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return
  public java.lang.Long getId();
    Code:
       0: new           #2                  // class java/lang/Long
       3: dup
       4: lconst_0
       5: invokespecial #3                  // Method java/lang/Long."<init>":(J)V
       8: areturn
  public java.lang.Object getId();
    Code:
       0: aload_0
       1: invokevirtual #4                  // Method getId:()Ljava/lang/Long;
       4: areturn
}
As you can see there are 2 methods for getId, one return type is Long as implementation and the another return type is Object type (it's invoking the Long getId method).
The return type Object method is for handling when no specify the generic type and bridge to Long getId method. Example:
    Id<Long> id = new Id<Long>() {
        @Override
        public Long getId() {
            return null;
        }
    };
    Long id1 = id.getId();
as the above code snippet we can implement the Id anonymous class with the Long type. but the problem we also can implement the Id anonymous class like without specify generic type in variable:
    Id id = new Id<Long>() {
        @Override
        public Long getId() {
            return null;
        }
    };
    Object id1 = id.getId();
so for now the compiler can't infer generic type for variable id, when id.getId() it's returning type Object type variable, it means it's calling this method public java.lang.Object getId(); and  bridge to public java.lang.Long getId(); method.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With