JDK 8 reflection changes (compared to JDK 7)

Paul Sandoz paul.sandoz at oracle.com
Tue Jan 28 03:16:39 PST 2014


Hi Pavel,

The second method is a bridge method (m.isBridge() == true).

You can use javap to see the byte code generated by the Java 8 compiler on the Test.B class:

  public void method(java.lang.Object);
    flags: ACC_PUBLIC, ACC_BRIDGE, ACC_SYNTHETIC
    Code:
      stack=2, locals=2, args_size=2
         0: aload_0       
         1: aload_1       
         2: checkcast     #2                  // class java/lang/String
         5: invokevirtual #3                  // Method method:(Ljava/lang/String;)V
         8: return        
      LineNumberTable:
        line 67: 0
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
               0       9     0  this   LTest$B;
    RuntimeVisibleAnnotations:
      0: #22()


Consider this code:

        B b = new B();
        A a = b; // raw type for A
        a.method("FOO"); // will invoke the bridge
        a.method(new Integer(1)); // ClassCastException

It was a bug that was fixed in 8:

  https://bugs.openjdk.java.net/browse/JDK-6695379

but has not been backported to a 7 update release, and i dunno if it will.

Often for EE/reflection-based frameworks it is sufficient to ignore and filter out the bridge methods when processing the classes to find invocation points of user classes to be invoked by the framework (IIRC that is what Jersey did).

Hth,
Paul.

On Jan 28, 2014, at 11:40 AM, Pavel Bucek <pavel.bucek at oracle.com> wrote:

> Hi all,
> 
> I hope this is correct mailing list - if not, please feel free to point me to different one.
> 
> Consider following code:
> 
>    @Retention(RetentionPolicy.RUNTIME)
>    @Target(ElementType.METHOD)
>    @interface C { }
> 
>    abstract class A<T> {
>        public abstract void method(T arg);
>    }
> 
>    class B extends A<String> {
>        @Override
>        @C
>        public void method(String arg) { }
>    }
> 
>    public static void main(String[] args) {
>        for(Method m : B.class.getMethods()) {
>            if(m.isAnnotationPresent(C.class)) {
>                System.out.println(m);
>            }
>        }
>    }
> 
> When executed on JDK8 (1.8.0-ea-b124), it prints out two methods:
> 
> public void org.glassfish.tyrus.test.standard_config.GenericClientEndpointTest$B.method(java.lang.String)
> public void org.glassfish.tyrus.test.standard_config.GenericClientEndpointTest$B.method(java.lang.Object)
> 
> result on JDK7 (just one method):
> 
> public void org.glassfish.tyrus.test.standard_config.GenericClientEndpointTest$B.method(java.lang.String)
> 
> Why is the method with Object param added to result set? And why it does have @C annotation declared? If this is intentional, is there any way how I could reliably filter out method with Object as parameter to get same result as on JDK7?
> 
> Thanks and regards,
> Pavel
> 



More information about the jdk8-dev mailing list