Generatoroptionen

JAXB / Jakarta Support

Ist die Einstellung generateJaxbSupport auf ClassicJXB, bzw. JakartaXmlBinding gesetzt, werden in allen Vertragsklassen JAXB-Annotationen generiert. JAXB[1] ist ein Framework, um Objekte als XML zu de-/serialisieren. Bis Java (EE) 8 war JAXB mit dem Package javax.xml.bind Teil des JDK, danach wurde es aus dem JDK entfernt und ist nun als Teil der von JEE zu Jakarta EE umbenannten Spezifikation als "Jakarta XML Binding" mit dem Package jakarta.xml.bind verfügbar. Dazu werden Annotationen an Klassen und Felder generiert:

@XmlRootElement(name = "Vertrag")
public class Vertrag {
 
  @XmlElement(name = "wohnflaeche", nillable = true)
  private Integer wohnflaeche;
 
  @XmlJavaTypeAdapter(value = LocalDateAdapter.class) (1)
  @XmlAttribute(name = "verkaufsStart")
  private LocalDate verkaufsStart;
 
  @XmlElement(name = "Deckung", type = org.faktorips.beispiel.modell.Deckung.class)
  @XmlElementWrapper(name = "Deckungen")
  private List<Deckung> deckungen;
 
  @XmlJavaTypeAdapter(value = ProductConfigurationXmlAdapter.class)
  @XmlAttribute(name = "product-component.id")
  private ProductConfiguration productConfiguration;

  // [...]

}
1 Der LocalDateAdapter wird bei Verwendung der Java-8-Variante des LocalDate generiert, für die veraltete Joda-Time-Variante muss ein eigener Adapter angelegt werden.

Um die dabei referenzierten Adapter (die JAXB nutzt, um komplexe Datentypen zu String-Repräsentationen zu mappen) muss ein spezieller JAXB-Context erstellt werden. Dies geschieht über die newJAXBContext-Methoden an einer zur JAXB-Version passenden JaxbSupport-Klasse. Diese bietet Faktor-IPS in den Modulen faktorips-runtime-javax-xml bzw. faktorips-runtime-jakarta-xml an:

// muss auch Modell-Repositories referenzieren
private IRuntimeRepository repository; (1)

private JAXBContext jaxbContext = JaxbSupport.INSTANCE.newJAXBContext(repository);  

private String toXml(Object obj) throws JAXBException {
  Marshaller marshaller = jaxbContext.createMarshaller();
  marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true); (2)
  StringWriter writer = new StringWriter();
  marshaller.marshal(obj, writer);
  return writer.toString();
}

private Object fromXml(String xml) throws JAXBException {
  Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
  unmarshaller.setAdapter(new
    ProductConfigurationXmlAdapter(repository));
  return unmarshaller.unmarshal(new StringReader(xml));
}
1 Das Repository muss die verwendeten Produkte beinhalten aber auch ggf. diesen zu Grunde liegende Modellprojekte referenzieren
2 Wenn das XML auch von Menschen, z.B. beim Debugging, gelesen wird ist eine Formatierung sinnvoll.

Sind im Projekt erweiterbare Aufzählungstypen definiert, wird für diese jeweils ein EnumXmlAdapter generiert. Dieser hat zwar einen (privaten) Konstruktor ohne Argumente, da manche JAXB-Implementierungen wie EclipseLink MOXy diesen erfordern, wird aber beim Erstellen des Faktor-IPS-JAXB-Contexts mit einer Referenz auf das Runtime-Repository initialisiert. Dies dient dazu, beim Deserialisieren die Werte aus dem Repository wiederzufinden.

Die Module mit JAXB-Support können an Stelle von faktorips-runtime eingebunden werden:

<dependency>
    <groupId>org.faktorips</groupId>
    <artifactId>faktorips-runtime-javax-xml</artifactId>
    <version>${faktorips.version}</version>
</dependency>

bzw.

<dependency>
    <groupId>org.faktorips</groupId>
    <artifactId>faktorips-runtime-jakarta-xml</artifactId>
    <version>${faktorips.version}</version>
</dependency>

Da JAXB als Teil von Java/Jakarta EE häufig schon als Teil eines Anwendungsservers ausgeliefert wird haben wir uns entschieden, die API nur als "provided" Dependency in den neuen Modulen einzubinden. Für Projekte, die nicht auf einem Java EE Server laufen kann es daher notwendig sein, auch für die API und eine Implementierung eine Projektabhängigkeit anzulegen:

<dependency>
    <groupId>javax.xml.bind</groupId>
    <artifactId>jaxb-api</artifactId>
    <version>2.3.1</version>
</dependency>
<dependency>
    <groupId>org.glassfish.jaxb</groupId>
    <artifactId>jaxb-runtime</artifactId>
    <version>2.3.7</version>
</dependency>

Mit Jakarta EE 10 wird Jakarta XML Binding 4 genutzt:

<dependency>
    <groupId>jakarta.xml.bind</groupId>
    <artifactId>jakarta.xml.bind-api</artifactId>
    <version>4.0.0</version>
</dependency>
<dependency>
    <groupId>org.glassfish.jaxb</groupId>
    <artifactId>jaxb-runtime</artifactId>
    <version>4.0.2</version>
</dependency>

Alternativ kann auch EclipseLink MOXy genutzt werden:

<dependency>
    <groupId>org.eclipse.persistence</groupId>
    <artifactId>org.eclipse.persistence.moxy</artifactId>
    <version>4.0.2</version>
</dependency>