Reputation:
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
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
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
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
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