Java Getriebe

Java und NetBeans

@ServiceProvider in einem JavaSE Projekt

Ich bin im Moment auf einem Annotation-Trip. Die Dinger sind cool. Vor allem in Zusammenhang mit ihren Processor Implementierungen. NetBeans macht es in seinen neusten Versionen selbst vor. So cool die XML Layer Strukturen zur Laufzeit auch sind, so uncool sind sie in dem Quellen zu pflegen. Dank des LayerGeneratingProcessors ist es aber verdammt einfach geworden Annotations (die ja bekanntlich direkt im Quelltext bei den betroffenen Klassen stehen) selber zu schreiben, die die notwendigen Einträge in der layer.xml erstellen.

Ein ähnliches leidiges Thema wie die XML Layer sind Services, die man selber in einer Textdatei unter META-INF/services pflegen darf. Auch hier bietet NetBeans von eine Annotation samt Processor bereit um diese Einträge direkt im Quelltext zu schreiben: @ServiceProvider.

In einer NetBeans RCP Anwendung ohne weiteres nutzbar und sogar zu bevorzugendes Mittel. Allerdings wäre so etwas in einer eigenen Standard Java Anwendung auch cool ((Um damit zum Beispiel eigene Processor Implementierungen zu registrieren.)). Ich hatte so etwas zwar auch schon mal selber geschrieben ((leider finde ich gerade die Quellen dazu nicht)) aber ganz so gut wie die NetBeans Implementierung war das dann doch nicht. Allerdings ist es relativ einfach möglich die Annotation von NetBeans in den eigenen Java SE Projekten zu nutzen:

Die größte Zauberei passiert in der project.properties des Projekts:

1
2
3
4
5
6
#alternativ kann auch ein absoluter Pfad angegeben werden. Ist aber nicht zu empfehlen.
nbplatform.active.dir=${nbplatform.NetBeans_IDE_7.0.1_(Build_201109201739).netbeans.dest.dir}
file.reference.org-openide-util-lookup.jar=\
    ${nbplatform.active.dir}/platform/lib/org-openide-util-lookup.jar
javac.classpath=\
    ${file.reference.org-openide-util-lookup.jar}

Hier passiert nichts weiter als die Lookup API aus dem NetBeans Installationsverzeichnis in den Klassenpfad des eigenen Projekts mit aufzunehmen. Die hier verwendete Schreibweise hat mindestens Zwei Vorteile:

  1. Sollte jemand anderes dieses Projekt auf einem anderen System übersetzen wollen/müssen, so reicht es völlig aus, die Variable nbplatform.active.dir in der eigenen private.properties mit dem für ihn korrekten Pfad zur NetBeans Platform einzutragen. Keine andere Einstellung muss geändert oder angepasst werden.
  2. Es lassen sich ohne weiteres zusätzliche Module aus der NetBeans Platform in den Klassenpfad aufnehmen. Mit der Variable ${nbplatform.active.dir} muss nur der Pfad innerhalb der Platforminstallation bekannt sein, was die Portabilität der Quellen auf ein anderes System deutlich erhöht.

Ich gebe zu, ich habe die Variable nbplatform.active.dir nicht aus purem Spaß so genannt. Wie es der Zufall ((. . .)) so will, wird in den Ant-Skripten eines NetBeans Moduls die aktuell verwendete NetBeans Platform in genau dieser Variable gespeichert. Zusammen mit der wrapped.xml aus dem Artikel Ein Wrappermodul für ein JavaSE Projekt kann man so in einem gekapselten Modul auch die Module der Platform selbst verwenden. Es reicht vollkommen aus, die beiden <propertyset> Elemente der <ant>-Tasks in den Zeilen 27 und 40 um ein weiteres <propertyref> zu erweitern:

1
2
3
4
<propertyset>
  <propertyref prefix="platforms."/>
  <propertyref prefix="nbplatform."/>
</propertyset>

… und schon verwendet das gekapselte Projekt automatisch die gleichen Modul-Jars wie das Modul selbst.

3 Responses to @ServiceProvider in einem JavaSE Projekt