user321068
user321068

Reputation:

Insert custom setter in maven-jaxb2-plugin

I'm using the org.jvnet.jaxb2.maven2:maven-jaxb2-plugin to create POJOs from XSD schema files.

Now I want to insert something like a custom setter. It should trim all Strings and should remove certain characters.

Do you know how to do this?


The XJB file:

<?xml version="1.0" encoding="UTF-8"?>
<jaxb:bindings version="2.0" xmlns:jaxb="http://java.sun.com/xml/ns/jaxb" xmlns:xsd="http://www.w3.org/2001/XMLSchema"
    xmlns:xs="http://www.w3.org/2001/XMLSchema" xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc">
    <jaxb:bindings schemaLocation="my-schema-xml4.xsd" node="/xs:schema">
        <xjc:javaType name="java.lang.String" adapter="my.StringAdapter" />
    </jaxb:bindings>
</jaxb:bindings>

Solution for binding Java types:

<?xml version="1.0" encoding="UTF-8" ?>
<bindings version="2.0" xmlns="http://java.sun.com/xml/ns/jaxb" xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:xjc="http://java.sun.com/xml/ns/jaxb/xjc">
    <bindings schemaLocation="mySchema-xml4.xsd" node="/xs:schema">
        <globalBindings>
            <xjc:javaType name="java.lang.String" xmlType="xs:string"
                adapter="com.name.MyAdapter" />
                    <xjc:javaType name="java.lang.String" xmlType="xs:anySimpleType"
                adapter="com.name.MyAdapter" />
        </globalBindings>
    </bindings>
</bindings>

But the @XmlJavaTypeAdapter still isn't added to the content property in nodes with mixed content, although the property has the type java.lang.String.

Upvotes: 4

Views: 3748

Answers (4)

Sunila Gollapudi
Sunila Gollapudi

Reputation: 41

In my opinion, you should use AOP, Pick Spring AOP, for instance, Intercept the Adapter methods to have trim / strip logic. In fact this can now be a generic logic that would apply to all string types. If this sounds convincing, I can further help with the code

Upvotes: 0

bdoughan
bdoughan

Reputation: 149017

An alternate approach would be to use a StAX StreamReaderDelegate to manipulate the XML text before it was received by the JAXB implementation.

Demo

Your code would look something like the following. You would implement a StreamReaderDelegate to manipulate the text returned from the text events:

package forum7329881;

import java.io.FileInputStream;
import javax.xml.bind.*;
import javax.xml.stream.*;
import javax.xml.stream.util.StreamReaderDelegate;

public class Demo {

    public static void main(String[] args) throws Exception {
        JAXBContext jc = JAXBContext.newInstance(Customer.class);

        XMLInputFactory xif = XMLInputFactory.newInstance();
        XMLStreamReader xsr = xif.createXMLStreamReader(new FileInputStream("src/forum7329881/input.xml"));
        xsr = new MyStreamReaderDelegate(xsr);

        Unmarshaller unmarshaller = jc.createUnmarshaller();
        Customer customer = (Customer) unmarshaller.unmarshal(xsr);

        Marshaller marshaller = jc.createMarshaller();
        marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
        marshaller.marshal(customer, System.out);
    }

    private static class MyStreamReaderDelegate extends StreamReaderDelegate {

        public MyStreamReaderDelegate(XMLStreamReader xsr) {
            super(xsr);
        }


        @Override
        public String getText() {
            return super.getText().trim();
        }

        @Override
        public char[] getTextCharacters() {
            return getText().toCharArray();
        }

        @Override
        public int getTextLength() {
            return getText().length();
        }

        @Override
        public int getTextStart() {
            return 0;
        }

    }

}

input.xml

Below is sample input that contains whitespace in the text nodes:

<customer Id="1">
    <name>    Jane Doe    </name>
    <address>
        <street>    123 A Street    </street>
    </address>
</customer>

Output

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<customer>
    <address>
        <street>123 A Street A</street>
    </address>
    <name>Jane Doe</name>
</customer>

Customer

package forum7329881;

import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement
public class Customer {

    private String name;
    private Address address;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Address getAddress() {
        return address;
    }

    public void setAddress(Address address) {
        this.address = address;
    }

}

Address

package forum7329881;

public class Address {

    private String street;

    public String getStreet() {
        return street;
    }

    public void setStreet(String street) {
        this.street = street;
    }

}

For More Information

Below is a link to a more detailed example where I used a StAX StreamReaderDelegate to support case insensitive unmarshalling:

Upvotes: 0

palacsint
palacsint

Reputation: 28865

If your XSD will not change in the future just generate the POJOs, comment out the JAXB plugin and modify the source by hand.

If your XSD changes rarely you still can use this solution with a version control system. Commit the generated source, modify the POJOs and commit the modifications. Next time when the XSD is modified generate a patch between the two commits, generate the POJOs from the new XSD and apply the patch. I found this solution a lot simpler in cases where the XSD almost never changes.

Upvotes: 0

lexicore
lexicore

Reputation: 43671

I think the best way to achieve this is to implement an own XmlAdapter and configure it via the property customization. You can do this with a standard jaxb:property customization or with the annotate plugin.

jaxb:property:

  <jaxb:property>
    <jaxb:baseType>
      <xjc:javaType name="java.lang.String"
        adapter="com.acme.foo.MyAdapter"/>
    </jaxb:baseType>
  </jaxb:property>

Annotate plugin:

  <annox:annotate target="field">
    <annox:annotate
      annox:class="javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter"
      value="com.acme.foo.MyAdapter"/>
  </annox:annotate>

See the sample project here:

https://svn.java.net/svn/jaxb2-commons~svn/basics/trunk/tests/one/

Upvotes: 2

Related Questions