Plugin für XJC, Teil 1

Plugin schreiben und starten:

Als erstes benötigen wir ein Plugin, dass bei der Code-Generierung des XJC-Tool aufgerufen wird. Das Plugin muss von der Klasse com.sun.tools.internal.xjc.Plugin erben. Unsere erste Version sieht wie folgt aus:

Unser erstes Plugin muss die folgenden Methoden implementieren:

  • getOptionName: diese Methode muss einen eindeutigen Namen für das Plugin zurück geben. Mittels diesem Namen kann das Plugin über die Komandozeile des XJC enabled bzw. disabled werden.
  • getUsage: Mit diese Methode gibt einen Hilfetext zurück, die beim Aufruf des XJC mit dem Parameter -help ausgegeben werden. Es werden keine weiteren Parameter unterstützt, sodass wir uns damit begnügen dem Benutzer zu sagen, wie er das Plugin enablen kann.
  • run: diese Methode wird während der Code-Generierung ausgeführt und ermöglicht das Verändern des erzeugten Code.

[code language=“java“]
package de.kue.sandbox.xjc;

import com.sun.tools.internal.xjc.Options;
import com.sun.tools.internal.xjc.Plugin;
import com.sun.tools.internal.xjc.outline.Outline;

public class PluginImpl extends Plugin {

@Override
public String getOptionName() {
return "Xcodeplugin";
}

@Override
public String getUsage() {
return "\t-Xcodeplugin\tenable";
}

@Override
public boolean run(Outline outline, Options opt, ErrorHandler errorHandler) throws SAXException {
System.out.println("run " + getOptionName() + " …");
System.out.println("run " + getOptionName() + " … done");
return true;
}
}
[/code]
Als nächstes müssen wir dem XJC-Tool das neue Plugin „unterjubeln“. Das XJC-Tool nutzt den ServiceLocator vom Java um neue Plugins zu finden. Aus diesem Grund muss das neue Plugin entsprechend angemeldet werden. Dafür wird im JAR die folgende Datei mit dem entsprechenden Pfad angelegt.

META-INF/services/com.sun.tools.internal.xjc.Plugin

Die Datei enthält pro Zeile den vollqualifizierten Pfad der neuen Plugins. In unserem Fall ist das der Name de.kue.sandbox.xjc.PluginImpl .
Als nächstes muss das JAR, welches das Plugin und die Service-Datei enthält, zum Classpath des XJC hinzugefügt werden.
Bei einem xjc -help sollte jetzt der oben angegebene Hilfetext zu lesen sein und bei der Code-Generierung sollte die Zeilen

run Xcodeplugin…
run Xcodeplugin… done

auftauchen, wenn man xjc -Xcodeplugin ... nutzt. Soweit so gut, der Teufel steckt im Detail.

Bei der Benutzung des JDK’s:

  • Das JDK hat eine eigene JAXB-Implementierung, die andere Packages verwendet als Standalone-Version. Bei der Entwicklung muss man das entsprechende tools.jar in den Classpath aufnehmen. Dort findet man dann die benötigten Klassen in einem Package mit dem Namen com.sun.tools.internal.xjc.*.
  • Das Plugin sollte mit dem gleichen JDK compiliert werden zu dem auch das XJC gehört. Damit ist man auf der sichereren Seite.
  • Auf einem Apple mit dem JDK 7 klappt das wie folgt: xjc -cp codeplugin.jar -help

Bei der Benutzung des Standalone JAXB Distribution:

  • Ich habe es nach zahllosen Versuchen und extrem debugging im XJC-Tool aufgegeben. Aus welchen Gründen auch immer werden die Klassen der JAXB Distribution mit einem anderen Classloader geladen als meine Plugin-Klasse und damit kann der Java ServiceLocator kein Plugin finden.
  • Christian Ullenboom konnte Licht ins Dunkel bringen: das Problem haben schon x andere gehabt: http://java.net/projects/jaxb/lists/users/archive/2005-06/message/6 und da die Antwort http://java.net/projects/jaxb/lists/users/archive/2005-06/message/12 . Danke für die spontane Klärung.

Bei der Benutzung von Maven/Ant:

  • Hier muss ich auf die entsprechend Doku der jeweiligen Plugins/Tasks verweisen. Dort wird beschrieben, wie man das erzeugte JAR in den Classpath des XJC-Tools bekommt.
  • Hier gilt aber auch, aufpassen bei den Namen der Packages und dem erzeugten Byte-Code.
  • Und soweit ich das sehen kann, gibt es auch hier Classloader-Problem.

Mit den Hilfen sollte es jetzt einfacher sein, das Plugin zum laufen zu bekommen. Ich habe es nur mit dem internen JDK 7 JAXB zum Laufen bekommen, aus diesem Grund nutze ich die „internal“ Packages.

Weitere Referenzen:

Schreibe einen Kommentar