Die Entwicklung des Parsers unter Nutzung der Reflection API ist relativ weit gut gegangen. Leider bin ich an eine Stelle gekommen an der ich keine andere Möglichkeit sah als die Struktur des Bytecodes doch noch ein zweites mal zu codifizieren ... und genau das wollte ich ja vermeiden. Der Wunsch nach Codegenerierung aus den Annotations wurde laut. Und genau das leisten Java Annotation Processors.
Ein Annotation Processor wird in den Compiliervorgang eingeklinkt und erweitert quasi den Compiler. Er kann Errors, Warnings und Code generieren. Das kann sowohl Sourcecode sein, der dann in einer weiteren Runde kompiliert wird, oder direkt Bytecode. Alle drei IDEs unterstützen Annotation Processoren, so dass die Portierbarkeit des Codes nicht eingeschränkt wird.
Natürlich wird die Umstellung die Entwicklungszeit verlängern. Lohnt sich dieser Aufwand? Da der Lernprozess für mich an dieser Arbeit mindestens ebenso wichtig ist wie das Ergebnis ist die Antwort "Ja". Hier folge ich dem Motto: "Sei Konservativ auf der Arbeit und tue was du bereits kannst, in der Freizeit ist Platz für Experimente!".
Ein Problem welches sich mir bei der Arbeit mit Annotation Processoren stellt ist die Testbarkeit derselben. End-To-End-Tests sind leicht zu realisieren, allerdings dauert der programmatische Aufruf des Compilers auf meinem, relativ aktuellen, System bereits eine halbe Sekunde. Das schränkt die Nutzbarkeit als TDD-Tests ein wenig ein. Und die API zu mocken ist relativ schwierig (kurze Diskussion: http://stackoverflow.com/questions/1811967/how-to-write-automated-unit-tests-for-java-annotation-processor). Sobald ich Sicherheit gewonnen habe wie ich hier vorgehe werde ich darüber berichten. Für einen kurzen Eindruck ... so sieht momentan mein Code aus für einen End-To-End-Test, der verifiziert das ein Error-Marker an einer bestimmten Stelle im Code erzeugt wurde.
@Test public void missingStructureAnnotationOnMainClass() throws Exception { SourceBuilder file = new SourceBuilder(); file.line("import com.idedeluxe.binary.*;"); file.line("@Binary ???class Foo {}"); assertMarkersAreGenerated(file); }
Hier wird sicher gestellt, dass ein Error Marker für die Klasse "Foo" erstellt wird. Intern wird dafür die Eingabe Analysiert, die Position(en) von "???" gespeichert und aus der Eingabe entfernt, der Compiler wird zusammen mit dem Annotation Processor auf die Eingabe angesetzt und es wird verifiziert, dass die Marker an der angegeben Stellen erzeugt werden (und keine Überflüssigen Marker erzeugt werden).

0 Kommentare:
Kommentar veröffentlichen