JAXB XmlAdapter via bindings file

2.8k views Asked by At

Consider this XSD:

<xsd:schema targetNamespace="http://foobar" xmlns:tns="http://foobar"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema">

    <xsd:complexType name="IdAttribute">
        <xsd:attribute name="id" type="xsd:token" />
    </xsd:complexType>

    <xsd:complexType name="FoobarType">
        <xsd:sequence>
            <xsd:element name="someIds" type="tns:IdAttribute" maxOccurs="unbounded" />
        </xsd:sequence>
    </xsd:complexType>

    <xsd:element name="Foobar" type="tns:FoobarType" />
</xsd:schema>

which results in the following, generated Java class:

@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "FoobarType", propOrder = {"someIds"})
public class FoobarType {

    @XmlElement(required = true)
    protected List<IdAttribute> someIds;

    // ...
}

Because IdAttribute only contains one String (id), I want to map these Strings directly into my FoobarType for easier usage. Therefore I wrote an XmlAdapter:

public class IdAttributeAdapter extends XmlAdapter<IdAttribute, String> { ... }

I've edited the generated class manually to verify my XmlAdapter works as expected (it does):

@XmlElement(required = true)
@XmlJavaTypeAdapter(IdAttributeAdapter.class)
protected List<String> someIds;

Of course I want to have this little code change done during code generation, so I've added the following bindings file (src/main/xjb/bindings.xjb):

Attempt 1:

<jaxb:bindings version="2.0" xmlns:jaxb="http://java.sun.com/xml/ns/jaxb" xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc"
    xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/jaxb http://java.sun.com/xml/ns/jaxb/bindingschema_2_0.xsd">

    <jaxb:bindings schemaLocation="../resources/xsd/foobar.xsd">
        <jaxb:bindings node="//xsd:complexType[@name='IdAttribute']">
            <xjc:javaType
                name="java.lang.String"
                adapter="org.foobar.IdAttributeAdapter" />
        </jaxb:bindings>
    </jaxb:bindings>

</jaxb:bindings>

Result

com.sun.istack.SAXParseException2; systemId: file:/C:/dev/foobar/src/main/xjb/bindings.xjb;
lineNumber: 12; columnNumber: 91;
compiler was unable to honor this conversion customization. It is attached to a wrong place, or its inconsistent with other bindings.

Attempt 2 (from here):

<jaxb:globalBindings xmlns:foo="http://foobar" xsi:schemaLocation="http://foobar ../resources/xsd/foobar.xsd">
    <xjc:javaType
        name="java.lang.String"
        xmlType="foo:IdAttribute"
        adapter="org.foobar.IdAttributeAdapter" />
</jaxb:globalBindings>

Result

com.sun.istack.SAXParseException2; systemId: file:/C:/dev/projects/luna/oasch/src/main/xjb/bindings.xjb;
lineNumber: 8; columnNumber: 112;
undefined simple type "{http://foobar}IdAttribute".

I've tried a few variations, but they all resulted in similar errors. So what's the correct way to add an XmlApender using a bindings file?

1

There are 1 answers

0
benjamin.donze On

What you try to do is wrong. You should replace fully the xml type IdAttribute with the java type String.

You will have to work with generic dom.Element type and convert it <-> String. Here is an exemple : JAXB @XmlAdapter for arbitrary XML for your case replace the java type Bar with String.

Other solution would be to add behavior to the generated class so that you add methods to your FoobarType to work as if it has a List of String
e.g. add methods
List<String> getIds()
void setIds(List<String>)

Here is a link that explain how you can do this : "Adding behavior"