2010-09-18 14 views
15

ich eine benutzerdefinierte Anmerkung enthält Metadaten für eine Eigenschaft geschrieben und ein AnnotationProcessor:Java 6 - Annotation-Prozessor und Code zusätzlich

@SupportedAnnotationTypes({"<package>.Property"}) 
public class PropertyProcessor extends AbstractProcessor { 

    @Override 
    public boolean process(Set<? extends TypeElement> annotations, 
      RoundEnvironment roundEnv) { 
     // Get messager object 
     Messager messager = processingEnv.getMessager(); 
     // Iterate through the annotations 
     for(TypeElement typeElement : annotations) { 
      // Iterate through the annotated elements 
      for(Element element : roundEnv.getElementsAnnotatedWith(typeElement)) { 
       // Get Property annotation 
       Property property = element.getAnnotation(Property.class); 

      } 
     } 
     return false; 
    } 

} 

Hier ist die Frage, habe ich Javassist vor, aber es war abhängig von den Klassenlader verwendet und ich denke, es ist nicht für OSGi-Anwendungen geeignet. Ich möchte den generierten Bytecode ändern, wenn eine Klasse mit Property Annotation kompiliert wird.

+0

eine Frage - warum wird das benötigt? Kann es nicht auf andere Weise erreicht werden? – Bozho

+0

ohne APT oder diese API zu verwenden, muss ich sowohl die Setter- als auch die Getter-Methode für jede Eigenschaft annotieren, aber wenn dies funktioniert, habe ich vollständige Kontrolle darüber, wie der Code generiert wird. das ist keine reine betriebsfrage, ich möchte wissen, ob das möglich ist oder nicht –

Antwort

5

Die kurze Antwort lautet: Sie sollten den Quellcode nicht während der Annotationsverarbeitung ändern.

Ich hatte kürzlich eine Situation, in der diese Antwort nicht zufriedenstellend war (siehe this question). Meine Lösung bestand darin, programmatisch den benötigten Code mit der internen javac-API hinzuzufügen. Einzelheiten finden Sie unter my answer to my own question.

Ich nahm die Inspiration dazu von Project Lombok, beginnend mit ihrem Quellcode und wegwerfen alles, was ich nicht brauchte. Ich glaube nicht, dass Sie einen viel besseren Ausgangspunkt finden.

BTW, wird wahrscheinlich nicht helfen JavaSist, weil Sie mit einem Quellbaum, nicht mit Byte-Code zu tun haben. Wenn Sie eine Bytecode-Manipulationsbibliothek verwenden möchten, können Sie das entweder statisch nach dem Kompilieren oder dynamisch beim Laden der Klassen tun, aber nicht während der Annotationsverarbeitung, da dies ein Vorkompilierungsschritt ist.

6

Haben Sie versucht ?

Mit Google Guice können Sie ein wenig aspektorientierte Programmierung durch Abfangen von Methoden durchführen. Wenn das alles ist, was Sie tun müssen, können Sie einen MethodInterceptor implementieren, mit dem Sie Methoden zur Laufzeit überschreiben können. Es ist wirklich nett, um übergreifende Bedenken zu isolieren.

Zum Beispiel kann sagen, dass Sie von einem bestimmten Verfahren zu verhindern, wollen am Wochenende ausgeführt werden, können Sie sie mit Anmerkungen versehen, wie so:

@Property 
public class SomeClass { 
    public Receipt doSometing() { 
     // Do something 
    } 
} 

definieren MethodInterceptor:

public class PropertyInterceptor implements MethodInterceptor { 
    public Object invoke(MethodInvocation invocation) throws Throwable { 
    // For example prevent the classes annotated with @Property 
    // from being called on weekends 
    Calendar today = new GregorianCalendar(); 
    if (today.getDisplayName(DAY_OF_WEEK, LONG, ENGLISH).startsWith("S")) { 
     throw new IllegalStateException(
      invocation.getMethod().getName() + " not allowed on weekends!"); 
    } 
    return invocation.proceed(); 
    } 
} 

Und dann binden die Abfangjäger der Anmerkung:

public class PropertyModule extends AbstractModule { 
    protected void configure() { 
     PropertyInterceptor propertyInterceptor = new PropertyInterceptor();   
     bindInterceptor(Matchers.annotatedWith(Property.class), 
     Matchers.any(), propertyInterceptor); 
    } 
} 
1

Annotation Verarbeitung nicht verändern gemeint existierende Klassen - es dient nur dazu, zusätzlichen Code/Ressourcen zu generieren (auf einer Klassen-zu-Klassen-Basis, sonst stößt man auf Probleme, wenn nur die modifizierten Quellen neu kompiliert werden).

Vor einiger Zeit habe ich Spoon für ein ähnliches Problem versucht: ich sehr die Idee eines Programmprozessors mochte (und die IDE-Integration noch mehr), aber es war zu der Zeit nicht wirklich stabil ...

Abhängig von Ihrem Anwendungsfall könnte ein AOP-Tool (zB: AspectJ) besser zu Ihnen passen als Spoon, und - natürlich - können Sie immer einen Quellcode-Generator verwenden oder ein vollwertiges DSL implementieren (werfen Sie einen Blick auf das fantastische Xtext) .

Je nach Größe, Fluktuationsrate und "geistiger Trägheit" Ihrer Teamkollegen - Sie könnten besser die Schmerzen von plain java anstatt die Einführung eines neuen Tools/Technologie, die Bildung von Mitarbeitern und die Integration der neues Werkzeug in Ihrem CI-System. Wägen Sie Kosten/Nutzen sorgfältig ab.