2014-12-22 21 views
9

Java 8 dispone di funzionalità denominate annotazioni Tipo (JSR 308). Mi piacerebbe usarlo per semplice framework di mappatura Object to Object. Vorrei definire annotazione @ExpectedType come questoCome utilizzare annotazioni di tipo personalizzato in Java

@Target({ElementType.TYPE_PARAMETER, ElementType.TYPE_USE}) 
@Retention(RetentionPolicy.RUNTIME) 
public @interface ExpectedType { 
    public Class<?> value(); 
} 

e poi utilizzarlo nel mio codice come questo:

public class SomeServiceImpl() { 
    public @ExpectedType(ObjectA_DTO.class) IObjectA doSomething(@ExpectedType(ObjectA_Entity.class) IObjectA obj) { 
     return (ObjectA_Entity) obj; // it's correct 
    } 
} 

IObjectA è un'interfaccia implementata da classi ObjectA_DTO e ObjectA_Entity. Il servizio Vorrei utilizzare in questo modo:

// it's correct 
assert someService.doSomething(new ObjectA_DTO()).getClass() == ObjectA_DTO.class; 

Vorrei cambiamento richiamo di metodi SomeServiceImpl usare mapper oggetto. Potrebbe essere ottenuto con il codice generato utilizzando JSR 269 o tramite AOP.

Il problema è che ho scritto un semplice processore di annotazioni e non gestisce affatto le annotazioni di tipo. La fonte di semplice elaboratore di annotazioni assomiglia a questo:

@SupportedAnnotationTypes("*") 
@SupportedSourceVersion(SourceVersion.RELEASE_8) 
public class SimpleAnnotationsProcessor extends AbstractProcessor { 

    public boolean process(Set<? extends TypeElement> annotations, RoundEnvironment roundEnv) { 
     Messager messager = processingEnv.getMessager(); 
     try { 
      for (TypeElement e : annotations) { 
       messager.printMessage(Diagnostic.Kind.NOTE, e.toString()); 
       for (Element elem : roundEnv.getElementsAnnotatedWith(e)) { 
        messager.printMessage(Diagnostic.Kind.NOTE, elem.toString()); 
       } 
      } 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 
     return true; 
    } 
} 

Delle idee come utilizzare o come accedere annotazioni di tipo da SimpleAnnotationsProcessor? L'utilizzo dell'API di elaborazione di annotazioni innestabili non è necessario per me, penso che avrebbe prestazioni migliori rispetto alla riflessione Java. Ad ogni modo non so come accedere all'annotazione del tipo tramite Java Reflection.

+0

Credo di essere chiaro quale obiettivo si sta cercando di raggiungere. Perché non creare solo la firma del metodo 'ObjectA_DTO doSomething (ObjectA_Entity)' se è quello che ti aspetti che faccia? –

+0

La firma del metodo non può essere così, perché mi piacerebbe usare un'istanza di servizio come questa 'someService.doSomething (new ObjectA_DTO())'. Voglio implementare object mapper per mappare 'ObjectA_DTO' su' ObjectA_Entity' e digitare annotation @ExpectedType definisce il tipo di destinazione. È la ragione per cui la firma deve essere "IObjectA doSomething (IObjectA)". –

+0

Ho appena ricevuto la tua domanda di passaggio ... Ho fatto un progetto semestrale sullo sviluppo della linea di prodotti in cui abbiamo elaborato le annotazioni. Per ora, ti lascerò con questo importante tutorial che mi ha fatto davvero andare sull'argomento (puoi saltare la parte 3 sulla generazione del codice) - https://deors.wordpress.com/2011/09/26/annotation-types/ più tardi, ricontrollerò questo post per i progressi. – ThisClark

risposta

2

io non sono sicuro di capire che cosa si prova a raggiungere, ma qui è un esempio di come è possibile accedere alle annotazioni con il Java API Reflection:

package test; 

import java.lang.annotation.Annotation; 
import java.lang.annotation.ElementType; 
import java.lang.annotation.Retention; 
import java.lang.annotation.RetentionPolicy; 
import java.lang.annotation.Target; 
import java.lang.reflect.AnnotatedType; 
import java.lang.reflect.Method; 

public class TypeParameterTest { 

    @Target({ElementType.TYPE_PARAMETER, ElementType.TYPE_USE}) 
    @Retention(RetentionPolicy.RUNTIME) 
    public @interface ExpectedType { 
     public Class<?> value(); 
    } 

    public static interface IObjectA {} 

    public static class ObjectA_DTO implements IObjectA {} 

    public static class ObjectA_Entity implements IObjectA {} 

    public static class SomeServiceImpl { 
     public @ExpectedType(ObjectA_DTO.class) IObjectA doSomething(@ExpectedType(ObjectA_Entity.class) IObjectA obj) { 
      return (ObjectA_Entity) obj; 
     } 
    } 

    public static void main(String[] args) throws NoSuchMethodException, SecurityException { 
     Method m = SomeServiceImpl.class.getMethod("doSomething", IObjectA.class); 
     AnnotatedType returnType = m.getAnnotatedReturnType(); 
     Annotation returnTypeAnnotation = returnType.getAnnotation(ExpectedType.class); 
     System.out.println(returnTypeAnnotation); 

     AnnotatedType[] parameters = m.getAnnotatedParameterTypes(); 
     for (AnnotatedType p : parameters) { 
      Annotation parameterAnnotation = p.getAnnotation(ExpectedType.class); 
      System.out.println(parameterAnnotation); 
     } 
    } 
} 

L'output è simile al seguente:

@test.TypeParameterTest$ExpectedType(value=class test.TypeParameterTest$ObjectA_DTO) 
@test.TypeParameterTest$ExpectedType(value=class test.TypeParameterTest$ObjectA_Entity) 

Nota, tuttavia, non tutte le annotazioni di tipo possibile sono accessibili tramite la reflection api, ma è sempre possibile leggerle dal codice byte se necessario (vedere la risposta here).

+0

Mi piacerebbe farlo usando il processore di annotazione perché potrebbe essere più veloce in fase di esecuzione e quindi di riflessione, comunque accetto la tua risposta. Il framework Checker può leggere annotazioni di tipo dal processore di annotazioni (non dal codice byte). Sai come sta? –

+0

Spiacente, non ho ancora usato il framework Checker. Non credo che i processori di annotazione sarebbero più veloci dell'uso della riflessione (non sono sicuro però). Ma non penserei ad alcuna ottimizzazione prima di incappare in problemi di prestazioni reali. Di solito la riflessione è abbastanza veloce ... – Balder

+0

Sai come accedere alle annotazioni di tipo per i tipi usati con le variabili locali tramite l'API di reflection? Qualcosa del tipo '@NotNull String str =" ";' o 'String str = (@Nullable String) null;' all'interno del metodo body? Vorrei usare l'annotazione '@ ExpectedType' come questa:' ObjectA_DTO aDto = (@ExpectedType ObjectA_DTO) someService.doSomething (...); ' –

0

Penso che stai mescolando l'uso delle annotazioni in fase di esecuzione rispetto all'uso delle stesse in fase di "compilazione" con vari strumenti. L'interfaccia Processor può essere utilizzata negli strumenti (compilatore, generatore javadoc), non nel codice di runtime.

+0

Voglio generare il codice per prestazioni migliori come MapStruct o Lombok invece di usando java reflection su runtime. –

0
@Documented 
@Retention(RetentionPolicy.RUNTIME) 
@Target(ElementType.FIELD) 
public @interface SearchDefinition { 

    public String identifier() default ""; 

} 

@SearchDefinition - può essere utilizzato ovunque

+1

Questa risposta è completamente errata. L'annotazione @Target (ElementType.FIELD) 'non può essere utilizzata da nessuna parte. Può essere utilizzato solo con i campi di classe. Se '@ Target' viene omesso, può essere utilizzato quasi ovunque tranne che per il cast di tipo (' (@SearchDefinition String) "abc" ') o di tipo generico (' List <@SearchDefinition String> '). –