I have an annotation
package javaannotationtest;
import java.lang.annotation.*;
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface CustomAnnotation {
}
This is applied to compareTo in following class
package javaannotationtest;
public class Customer implements Comparable<Customer>{
@Override
@CustomAnnotation
public int compareTo(Customer o) {
return 0;
}
}
The class gives different result with java-7 and java-8 compiled code.
Java 7
1.7.0_45 -> public int javaannotationtest.Customer.compareTo(javaannotationtest.Customer)
has annotation of type javaannotationtest.CustomAnnotation
1.7.0_45 -> public int javaannotationtest.Customer.compareTo(java.lang.Object)
has no annotation of type javaannotationtest.CustomAnnotation
Note that compareTo(Object) does not have the annotation.
Java 8
1.8.0 -> public int javaannotationtest.Customer.compareTo(javaannotationtest.Customer)
has annotation of type javaannotationtest.CustomAnnotation
1.8.0 -> public int javaannotationtest.Customer.compareTo(java.lang.Object)
has annotation of type javaannotationtest.CustomAnnotation
Java 8 has annotation added to the compareTo(java.lang.Object)
method
Here is output from javap for the version compiled with Java 8 (probably not relevant, it shows the annotation added to both methods)
Classfile /C:/code/java8annoation/out/production/java8annoation/javaannotationtest/Customer.class
Last modified 17 Apr, 2014; size 719 bytes
MD5 checksum 678e0371f5f9ed5666b513c940f365a7
Compiled from "Customer.java"
public class javaannotationtest.Customer extends java.lang.Object implements java.lang.Comparable<javaannotationtest.Customer>
Signature: #20 // Ljava/lang/Object;Ljava/lang/Comparable<Ljavaannotationtest/Customer;>;
SourceFile: "Customer.java"
minor version: 0
major version: 52
flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
#1 = Methodref #4.#23 // java/lang/Object."<init>":()V
#2 = Class #24 // javaannotationtest/Customer
#3 = Methodref #2.#25 // javaannotationtest/Customer.compareTo:(Ljavaannotationtest/Customer;)I
#4 = Class #26 // java/lang/Object
#5 = Class #27 // java/lang/Comparable
#6 = Utf8 <init>
#7 = Utf8 ()V
#8 = Utf8 Code
#9 = Utf8 LineNumberTable
#10 = Utf8 LocalVariableTable
#11 = Utf8 this
#12 = Utf8 Ljavaannotationtest/Customer;
#13 = Utf8 compareTo
#14 = Utf8 (Ljavaannotationtest/Customer;)I
#15 = Utf8 o
#16 = Utf8 RuntimeVisibleAnnotations
#17 = Utf8 Ljavaannotationtest/CustomAnnotation;
#18 = Utf8 (Ljava/lang/Object;)I
#19 = Utf8 Signature
#20 = Utf8 Ljava/lang/Object;Ljava/lang/Comparable<Ljavaannotationtest/Customer;>;
#21 = Utf8 SourceFile
#22 = Utf8 Customer.java
#23 = NameAndType #6:#7 // "<init>":()V
#24 = Utf8 javaannotationtest/Customer
#25 = NameAndType #13:#14 // compareTo:(Ljavaannotationtest/Customer;)I
#26 = Utf8 java/lang/Object
#27 = Utf8 java/lang/Comparable
{
public javaannotationtest.Customer();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
LineNumberTable:
line 3: 0
LocalVariableTable:
Start Length Slot Name Signature
0 5 0 this Ljavaannotationtest/Customer;
public int compareTo(javaannotationtest.Customer);
descriptor: (Ljavaannotationtest/Customer;)I
flags: ACC_PUBLIC
Code:
stack=1, locals=2, args_size=2
0: iconst_0
1: ireturn
LineNumberTable:
line 7: 0
LocalVariableTable:
Start Length Slot Name Signature
0 2 0 this Ljavaannotationtest/Customer;
0 2 1 o Ljavaannotationtest/Customer;
RuntimeVisibleAnnotations:
0: #17()
public int compareTo(java.lang.Object);
descriptor: (Ljava/lang/Object;)I
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 javaannotationtest/Customer
5: invokevirtual #3 // Method compareTo:(Ljavaannotationtest/Customer;)I
8: ireturn
LineNumberTable:
line 3: 0
LocalVariableTable:
Start Length Slot Name Signature
0 9 0 this Ljavaannotationtest/Customer;
RuntimeVisibleAnnotations:
0: #17()
}
Could someone explain relevant changes in Java 8? (Will offer Bounty when is becomes eligible).
This change is described in the issue JDK-6695379 - Copy method annotations and parameter annotations to synthetic bridge methods. There doesn't seem to be much discussion about this feature but the request and justification do make sense to me.
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.
It is also documented in the JDK 8 compatibility guide:
Area: Tools / javac
Synopsis
As of this release, 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.
Nature of Incompatibility
behavioralRFE
6695379
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