2014-04-17 19 views
10

Ho un'annotazionejava8 - annotare compareTo <T> di paragonabile <T> aggiunge annotazioni a compareTo (Object o)

package javaannotationtest; 

import java.lang.annotation.*; 

@Target({ElementType.METHOD}) 
@Retention(RetentionPolicy.RUNTIME) 
public @interface CustomAnnotation { 
} 

Si applica al compareTo nella seguente classe

package javaannotationtest; 

public class Customer implements Comparable<Customer>{ 
    @Override 
    @CustomAnnotation 
    public int compareTo(Customer o) { 
     return 0; 
    } 
} 

La classe dà risultati diversi con codice compilato java-7 e java-8.

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 

noti che compareTo (Object) non ha l'annotazione.

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 ha l'annotazione aggiunta alla compareTo(java.lang.Object) metodo di

Qui viene emesso dal javap per la versione compilata con Java 8 (probabilmente non rilevante, mostra l'annotazione aggiunto entrambi i metodi)

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() 
} 

Qualcuno potrebbe spiegare modifiche rilevanti in Java 8? (Offrirà Bounty quando diventa idoneo).

+0

Non capisco la domanda. Quali cambiamenti rilevanti stai chiedendo? A questo proposito, l'annotazione è su entrambi i metodi in entrambe le versioni java. –

+0

No. In java 7, java8.Customer.compareTo (java.lang.Object) non ha l'annotazione. (Modificare la domanda per chiarire) – Jayan

risposta

8

Questa modifica è descritta nel numero JDK-6695379 - Copy method annotations and parameter annotations to synthetic bridge methods. Non sembra esserci molta discussione su questa funzione, ma la richiesta e la giustificazione hanno senso per me.

DESCRIZIONE DELLA DOMANDA: Quando una classe estende a classi generiche o implementa un'interfaccia generica, metodo sintetico può essere generato per colmare tra il metodo prendendo specifico parametri/ritorno e quella del super-classe/interfaccia che è definita con Oggetti, a causa della cancellazione. Un metodo bridge reindirizza la chiamata al metodo effettivo, in base alla specifica del linguaggio Java. Tuttavia, il metodo bridge non ha le annotazioni definite per il metodo originale e i suoi parametri.

GIUSTIFICAZIONE: Il problema si pone quando si tenta di recuperare annotazioni di tale metodo in fase di esecuzione. Poiché è impossibile scoprire in modo affidabile quali classi sostituiscano i parametri generici, non sappiamo quale parametro inviare a getMethod (...) per ricevere il metodo corretto. Quando si invia Object.class (mentre il parametro generico è una classe diversa) getMethod restituirà il metodo bridge, che non avrà le informazioni sulle annotazioni del metodo originale.

È anche documentato nella JDK 8 compatibility guide:

Area: Strumenti/javac

Trama
In questa versione, il parametro e il metodo annotazioni vengono copiati ponte sintetica metodi.Questa correzione implica che ora programmi come:

@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 {} 

} 

Ogni metodo ponte generato avrà tutte le annotazioni del metodo che reindirizza a. Verranno copiate anche le annotazioni dei parametri. Questa modifica del comportamento potrebbe influire sul processore di annotazioni o in generale su qualsiasi applicazione che utilizza le annotazioni.

Natura di incompatibilità
comportamentale

RFE
6695379

+0

@kapep, solo curioso, come hai scoperto che questo era il changeset specifico? –

+0

@vrz Ci è voluto del tempo per trovarlo :) I changelog non contenevano molte annotazioni e non erano abbastanza dettagliati. Le bandiere "ACC_BRIDGE, ACC_SYNTHETIC" nel bytecode mi hanno fatto incuriosire e mi sembravano pertinenti. Penso di aver cercato su google qualcosa come "annotazioni java 8 su metodi sintetici". – Kapep

+0

@kappep, vedo, grazie per la tua risposta. Sono l'autore del changeset a cui hai fatto riferimento nella tua risposta. Stavo chiedendo di sapere come posso facilitare il compito di trovare un determinato changeset per gli utenti esterni. Sembra che aggiungere ulteriori commenti al changeset/codice possa essere d'aiuto, ma sono aperto a suggetions/ideas. –

3

@kapep: risposta molto bello. Vorrei aggiungere alcune informazioni complementari su questo problema. Non solo le annotazioni vengono copiate sul metodo bridge. Anche i nomi dei parametri vengono copiati. Se si compila l'esempio con l'opzione -parameters compiler si ottiene questo output javap:

public int compareTo(Customer); 
descriptor: (LCustomer;)I 
flags: ACC_PUBLIC 
Code: 
    stack=1, locals=2, args_size=2 
    0: iconst_0  
    1: ireturn  
    LineNumberTable: 
    line 11: 0 
MethodParameters: 
    Name       Flags 
    o        
RuntimeVisibleAnnotations: 
    0: #15() 

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 Customer 
    5: invokevirtual #3     // Method compareTo:(LCustomer;)I 
    8: ireturn  
    LineNumberTable: 
    line 7: 0 
MethodParameters: 
    Name       Flags 
    o        synthetic <-- see the name copied to the bridge method 
RuntimeVisibleAnnotations: 
    0: #15() 
Problemi correlati