United StatesChange Country, Oracle Worldwide Web Sites Communities I am a... I want to...
JDK-6695379 : Copy method annotations and parameter annotations to synthetic bridge methods

Details
Type:
Enhancement
Submit Date:
2008-04-29
Status:
Closed
Updated Date:
2014-05-08
Project Name:
JDK
Resolved Date:
2013-06-01
Component:
tools
OS:
windows_xp
Sub-Component:
javac
CPU:
x86
Priority:
P5
Resolution:
Fixed
Affected Versions:
6
Fixed Versions:

Related Reports
Relates:
Relates:
Relates:
Relates:
Relates:
Relates:

Sub Tasks

Description
A DESCRIPTION OF THE REQUEST :
When a class extends a generic classes or implements a generic interface, synthetic method may be generated to bridge between the method taking specific parameters/return and the one of the super-class/interface which is defined with Objects, because of erasure. A bridge method redirects the call to the actual method, according to Java Language Specification. However the bridge method lacks  the annotations defined for the original method and its parameters.

JUSTIFICATION :
The problem arises when trying to retrieve annotations of such a method at run-time. Since it's impossible to find out reliably what classes substitute the generic parameters, we don't know what parameter to send to getMethod(...) in order to receive the correct method back. When sending Object.class (while generic parameter is a different class) getMethod will return the bridge method, which won't have the information about the original method annotations.

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
Annotation with run-time retention should be copied by javac to bridge methods.
ACTUAL -
Bridge method has no annotations.

---------- BEGIN SOURCE ----------
public interface Transform<A,B> {
  B transform(A a);
}
public class DigitCount<Integer,Integer> {
  public Integer transform(@Nullable Integer i) {
    return i == null ? 0 : i.toString().length();
  }
}
public class TestMe {
  public static void main(String[] args) {
    boolean hasAnnotation = false;
    try {
       Class c = Class.forName(args[0]);
       if (!Transform.class.isAssignableFrom(c)) return;
       Method m = c.getMethod("transform", Object.class);
       Annotation[] anot = m.getParameterAnnotations()[0];
       for (Annotation a: anot) {
         if (a.annotationType().equals(Nullable.class)) hasAnnotation = true;
       }
    } catch (Exception e) {
      e.printStackTrace();
    }
    System.out.println(hasAnnotation);
  }
}

//run TestMe DigitCount
---------- END SOURCE ----------

CUSTOMER SUBMITTED WORKAROUND :
It is possible sometimes to retrieve the right class for the parameter using the technique described by Neal Gafter here: http://gafter.blogspot.com/2006/12/super-type-tokens.html. Only instead of getGenericSuperclass(), getGenericInterfaces() can be used, and the one which corresponds to Transform will be interrogated for its types.

However it won't work for following example:

public class AsString<T> implements Transform<T,String> {
    public String transform(T t) {
      return t.toString();
    }
 }
public class IntegerAsString extends AsString<Integer> {
    public String transform(@Nullable Integer i) {
      return i == null ? null : i.toString();
    }
}

It will work if IntegerAsString is defined to explicitly implement Transform<Integer,String>.

                                    

Comments
Respective test:
tools/javac/6889255/T6889255.java
tools/javac/MethodParameters/ClassFileVisitor.java
tools/javac/MethodParameters/ReflectionVisitor.java
tools/javac/MethodParameters/Tester.java
tools/javac/T6695379/AnnotationsAreNotCopiedToBridgeMethodsTest.java	
                                     
2013-06-19
Parameter and method annotations are copied to synthetic bridge methods.

This fix implies that now for programs like:

    @Target(value = {ElementType.PARAMETER})
    @Retention(RetentionPolicy.RUNTIME)
    @interface ParamAnnotation {}

    @Target(value = {ElementType.METHOD})
    @Retention(RetentionPolicy.RUNTIME)
    @interface MethodAnnotation {}

    abstract class T<A,B> {
        B m(A a){return null;}
     }

     class CovariantReturnType extends T<Integer, Integer> {
         @MethodAnnotation
         Integer m(@ParamAnnotation Integer i) {
             return i;
         }

        public class VisibilityChange extends CovariantReturnType {}

    } 

Each generated bridge method will have all the annotations of the method it redirects to. Parameter annotations will also be copied. This change in the behavior may impact some annotations processor or in general any application that use the annotations.
                                     
2013-11-21
waiting for ccc approval
                                     
2013-04-09
This patch is waiting for bug JDK-8011026 to be solved. The feature is needed for testing.
                                     
2013-04-10
URL:   http://hg.openjdk.java.net/jdk8/tl/langtools/rev/ec871c3e8337
User:  vromero
Date:  2013-06-01 21:10:20 +0000

                                     
2013-06-01
URL:   http://hg.openjdk.java.net/jdk8/jdk8/langtools/rev/ec871c3e8337
User:  lana
Date:  2013-06-11 18:27:02 +0000

                                     
2013-06-11



Hardware and Software, Engineered to Work Together