This plugin provides some extra (missing) XJC features to generated Java Beans.
Add this library to the JAXB compiler plugin and activate the respective plugins.
<plugin>
<groupId>org.jvnet.jaxb</groupId>
<artifactId>jaxb-maven-plugin</artifactId>
<configuration>
<extension>true</extension>
<plugins>
<plugin>
<groupId>io.fares.bind.xjc.plugins</groupId>
<artifactId>extras-xjc-plugin</artifactId>
<version>1.0.2</version>
</plugin>
</plugins>
<args>
<arg>-Xxml-adapter</arg>
</args>
</configuration>
</plugin>
This plugin can also be used to "override" XJC adapters that have been attached to a simple type in the global bindings.
<jaxb:globalBindings>
<xjc:javaType name="java.time.OffsetDateTime"
xmlType="xsd:dateTime"
adapter="test.time.OffsetDateTimeAdapter"/>
</jaxb:globalBindings>
To override the default adapter binding just add the extras:xml-adapter
annotations to either xsd:element
or xsd:attribute
:
<xsd:schema targetNamespace="urn:replacesimpletype.test"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:jaxb="https://jakarta.ee/xml/ns/jaxb"
xmlns:xjc ="http://java.sun.com/xml/ns/jaxb/xjc"
xmlns:extras="urn:jaxb.fares.io:extras"
elementFormDefault="qualified"
jaxb:version="3.0"
jaxb:extensionBindingPrefixes="xjc extras">
<xsd:annotation>
<xsd:appinfo>
<jaxb:globalBindings fixedAttributeAsConstantProperty="true">
<xjc:javaType name="java.time.OffsetDateTime"
xmlType="xsd:dateTime"
adapter="test.time.OffsetDateTimeAdapter"/>
</jaxb:globalBindings>
</xsd:appinfo>
</xsd:annotation>
<xsd:complexType name="Book">
<xsd:sequence>
<xsd:element name="overrideElement" type="xsd:dateTime">
<xsd:annotation>
<xsd:appinfo>
<extras:xml-adapter name="test.time.LocalDateTimeAdapter"/>
</xsd:appinfo>
</xsd:annotation>
</xsd:element>
</xsd:sequence>
<xsd:attribute name="overrideAttribute" type="xsd:dateTime">
<xsd:annotation>
<xsd:appinfo>
<extras:xml-adapter name="test.time.LocalDateTimeAdapter"/>
</xsd:appinfo>
</xsd:annotation>
</xsd:attribute>
</xsd:complexType>
<xsd:attribute name="refAttribute1" type="xsd:dateTime"/>
<xsd:attribute name="refAttribute2" type="xsd:string"/>
<!-- this one currently would not work -->
<xsd:attribute name="refAttribute3" type="xsd:dateTime">
<xsd:annotation>
<xsd:appinfo>
<extras:xml-adapter name="test.time.LocalDateTimeAdapter"/>
</xsd:appinfo>
</xsd:annotation>
</xsd:attribute>
</xsd:schema>
Note: Annotations on the ref attribute currently do not work
For some reason, XJC does not allow global bindings of complex types. Below will fail with an error message com.sun.istack.SAXParseException2: undefined simple type "{urn:complextypeadapter.test}Amount"
:
<jaxb:globalBindings>
<xjc:javaType name="javax.money.MonetaryAmount"
xmlType="c:Amount"
adapter="test.complextypeadapter.AmountXmlAdapter"/>
</jaxb:globalBindings>
Unfortunately XJC does not support custom XJC plugin extensions for globalBindings
. The best we can do is either attach customisations to a schema or to the target type we want to map.
Below example will attach a customisation to the complex type that we want to map using the AmountXmlAdapter
. The plugin will process every generated field and if the field is of xml type c:Amount
, it will attach the XmlAdapter
as specified in extras:xml-adapter/@name
. It will also ensure that the type of the field exactly matches the custom type of the XmlAdapter
to prevent extended types to be wrongly adapted to prevent loss of data.
<xsd:schema targetNamespace="urn:complextypeadapter.test"
xmlns:tns="urn:complextypeadapter.test"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:jaxb="https://jakarta.ee/xml/ns/jaxb"
xmlns:extras="urn:jaxb.fares.io:extras"
jaxb:version="3.0"
jaxb:extensionBindingPrefixes="extras">
<xsd:element name="Amount" type="tns:Amount"/>
<xsd:complexType name="Amount">
<xsd:annotation>
<xsd:appinfo>
<extras:xml-adapter name="test.complextypeadapter.AmountXmlAdapter"/>
</xsd:appinfo>
</xsd:annotation>
<xsd:simpleContent>
<xsd:extension base="xsd:decimal">
<xsd:attribute name="currency" type="tns:CurrencyCode" use="required">
<xsd:annotation>
<xsd:documentation>The ISO 4217 compliant currency code the currency ammount is nominated in.</xsd:documentation>
</xsd:annotation>
</xsd:attribute>
</xsd:extension>
</xsd:simpleContent>
</xsd:complexType>
<xsd:simpleType name="CurrencyCode">
<xsd:annotation>
<xsd:documentation>Use ISO 4217 three letter alpha code. </xsd:documentation>
</xsd:annotation>
<xsd:restriction base="xsd:string">
<xsd:pattern value="[A-Z]{3}"/>
</xsd:restriction>
</xsd:simpleType>
</xsd:schema>
When using this type in another schema, the generate a field is of type javax.money.MonetaryAmount
instead of the corresponding generated XML type and the relevant @XmlJavaTypeAdapter
annotation is in place.
<xsd:schema targetNamespace="urn:book.test"
xmlns:c="urn:complextypeadapter.test"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:import namespace="urn:complextypeadapter.test" schemaLocation="Amount.xsd" />
<xsd:complexType name="Book">
<xsd:sequence>
<xsd:element name="isbn" type="xsd:string" />
<xsd:element name="price" type="c:Amount" />
</xsd:sequence>
</xsd:complexType>
</xsd:schema>
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "Book", propOrder = {
"isbn",
"price"
})
public class Book {
@XmlElement(required = true)
protected String isbn;
@XmlElement(required = true, type = Amount.class)
@XmlJavaTypeAdapter(AmountXmlAdapter.class)
protected MonetaryAmount price;
...
}