2014-12-22 10 views
9

Java 8 verfügt über eine Funktion namens Typ Anmerkungen (JSR 308). Ich würde es gerne für ein einfaches Objekt-zu-Objekt-Mapper-Framework verwenden. Ich möchte Anmerkung @ExpectedType wie dieseVerwendung benutzerdefinierter Anmerkungen in Java

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

definieren und sie dann wie dies in meinem Code verwenden:

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

IObjectA eine Schnittstelle von Klassen ObjectA_DTO und ObjectA_Entity implementiert ist. Der Service Ich mag würde auf diese Weise verwenden:

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

Ich würde ändern Aufruf von SomeServiceImpl Methoden wie Object Mapper zu verwenden. Dies könnte durch generierten Code unter Verwendung von JSR 269 oder durch AOP erreicht werden.

Das Problem ist, schrieb ich einfache Annotationen Prozessor und es behandelt überhaupt keine Typ Anmerkungen. Die Quelle von einfachen Anmerkungen Prozessor sieht wie folgt aus:

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

Irgendwelche Ideen, wie oder zu verwenden, wie Typenannotationen von SimpleAnnotationsProcessor zugreifen? Die Verwendung der Pluggable Annotation Processing API ist für mich nicht notwendig. Ich denke, sie hätte eine bessere Leistung als Java Reflection. Wie auch immer, ich weiß nicht, wie ich über Java Reflection auf den Typ Annotation zugreifen kann.

+0

verwendet werden, ich denke, ich bin unklar, welches Ziel Sie erreichen wollen. Warum nicht einfach die Methodensignatur 'ObjectA_DTO doSomething (ObjectA_Entity) 'machen, wenn Sie das erwarten? –

+0

Methodensignatur kann nicht so sein, weil ich Dienstinstanz wie dieses 'someService.doSomething (neues ObjectA_DTO())' verwenden möchte. Ich möchte den Object Mapper implementieren, um 'ObjectA_DTO' auf' ObjectA_Entity' abzubilden und Annotation zu schreiben. @ExpectedType definiert den Zieltyp. Aus diesem Grund muss die Signatur "IObjectA doSomething (IObjectA)" sein. –

+0

Ich habe gerade Ihre Frage kurz gefasst ... Ich habe ein Semester Projekt zur Entwicklung von Produktlinien gemacht, wo wir Anmerkungen verarbeitet haben. Für den Moment werde ich Sie mit diesem wichtigen Tutorial verlassen, das mich wirklich zum Thema gebracht hat (Sie können Teil 3 über die Codegenerierung überspringen) - https://deors.wordpress.com/2011/09/26/annotation-types/ später werde ich diesen Beitrag erneut auf Fortschritte überprüfen. – ThisClark

Antwort

2

Ich bin nicht sicher, ich verstehe, was Sie versuchen, zu erreichen, aber hier ist ein Beispiel, wie Sie Ihre Anmerkungen mit dem Java-Reflection-API zugreifen:

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

Die Ausgabe sieht wie folgt aus:

Beachten Sie, dass nicht alle möglichen Typ Anmerkungen durch die Reflektions-API zugänglich sind, aber Sie können sie immer aus dem Byte-Code lesen, wenn nötig (siehe meine Antwort here).

+0

Ich möchte es mit Annotation Prozessor tun, weil es in der Laufzeit schneller als Reflexion sein könnte, trotzdem akzeptiere ich Ihre Antwort. Checker-Framework kann Typanmerkungen vom Annotationsprozessor lesen (nicht vom Bytecode). Weißt du wie es geht? –

+0

Entschuldigung, ich habe das Checker-Framework noch nicht benutzt. Ich glaube nicht, dass Annotationsprozessoren schneller wären als Reflektion (nicht sicher). Aber ich würde nicht über irgendwelche Optimierungen nachdenken, bevor ich auf tatsächliche Leistungsprobleme stoße. In der Regel ist die Reflektion schnell genug ... – Balder

+0

Wissen Sie, wie Sie auf Typenanmerkungen für Typen zugreifen können, die mit lokalen Variablen über die Reflektions-API verwendet werden? So etwas wie '@NotNull String str = ""; 'oder' String str = (@Nullable String) null; 'innerhalb des Methodenrumpfs? Ich möchte '@ ExpectedType'-Annotation wie folgt verwenden: 'ObjectA_DTO aDto = (@ExpectedType ObjectA_DTO) someService.doSomething (...);' –

0

Ich denke, Sie vermischen die Verwendung von Anmerkungen zur Laufzeit gegen die Verwendung derselben zur "Kompilierzeit" durch verschiedene Tools. Processor Schnittstelle ist für den Einsatz in Tools (Compiler, Javadoc-Generator), nicht in Ihrem Laufzeitcode.

+0

Ich möchte den Code für bessere Leistung generieren, wie MapStruct oder Lombok statt Java-Reflektion zur Laufzeit verwenden. –

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

    public String identifier() default ""; 

} 

@SearchDefinition - kann überall

+1

Diese Antwort ist völlig falsch '@Target (ElementType.FIELD)' Anmerkung kann nicht überall verwendet werden. Es kann nur mit Klassenfeldern verwendet werden. Wenn '@ Target' weggelassen wird, kann es fast überall außer type cast ('(@SearchDefinition String)" abc "') oder generischer Typ ('List <@SearchDefinition String>') verwendet werden. –

Verwandte Themen