How to disable Java Naming Conventions in xjc? - jaxb

For example sOmE_PROPerty in xsd must be sOmE_PROPerty in java class not someProperty.
I tried to use globalBindings enableJavaNamingConventions="false" but it doesn't work.

You will need to use underscoreBinding="asCharInWord" instead of enableJavaNamingConventions="false":
customer.xsd
<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema
targetNamespace="http://www.example.org/customer"
xmlns="http://www.example.org/customer"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
elementFormDefault="qualified">
<xsd:complexType name="customer">
<xsd:sequence>
<xsd:element name="sOmE_PROPerty" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
</xsd:schema>
binding.xml
A JAXB binding file is used to customize the schema to Java conversion:
<jaxb:bindings
xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
version="2.1">
<jaxb:globalBindings underscoreBinding="asCharInWord"/>
</jaxb:bindings>
XJC Call
xjc -d out -b binding.xml customer.xsd
Customer
The generated property names now include the underscore character:
package org.example.customer;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlType;
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "customer", propOrder = {
"sOmEPROPerty"
})
public class Customer {
#XmlElement(name = "sOmE_PROPerty", required = true)
protected String sOmEPROPerty;
public String getSOmE_PROPerty() {
return sOmEPROPerty;
}
public void setSOmE_PROPerty(String value) {
this.sOmEPROPerty = value;
}
}
Without Using binding.xml
If you instead make the following XJC call:
xjc -d out -customer.xsd
You will see that the generated properties do not include the underscore:
package org.example.customer;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlType;
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "customer", propOrder = {
"sOmEPROPerty"
})
public class Customer {
#XmlElement(name = "sOmE_PROPerty", required = true)
protected String sOmEPROPerty;
public String getSOmEPROPerty() {
return sOmEPROPerty;
}
public void setSOmEPROPerty(String value) {
this.sOmEPROPerty = value;
}
}

Solved by changing source code of jaxb in class com.sun.xml.bind.api.impl.NameConverter like this:
public static final NameConverter standard = new Standard();
static class Standard extends NameUtil implements NameConverter {
public String toClassName(String s) {
return s;//toMixedCaseName(toWordList(s), true);
}
public String toVariableName(String s) {
return s;//toMixedCaseName(toWordList(s), false);
}
public String toInterfaceName( String token ) {
return token;//toClassName(token);
}
public String toPropertyName(String s) {
String prop = s;//toClassName(s);
// property name "Class" with collide with Object.getClass,
// so escape this.
if(prop.equals("Class"))
prop = "Clazz";
return prop;
}

Related

Create xml string for java jaxb bean with Root class & inner classes having different name spaces

I have a Root Class called Employee, which has two elements empid and name and another jaxb class called Address. Below is the sample snippet.
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "Request",propOrder = {
"header",
"body",
"signature"
})
#XmlRootElement(name="Employee")
public class Employee
implements Serializable
{
#XmlElement(name = "Header", required = true)
protected String empId;
#XmlElement(name = "Body", required = true)
protected String empName;
#XmlElement(name = "Address", required = true)
protected Address address;
.. setters and getters
}
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "Address", propOrder = {
"streetLine1",
"streetLine2",
})
#XmlRootElement(name="Address",namespace= "http://www.w3.org/2000/09/xmldsig#")
public class Employee
implements Serializable
{
private final static long serialVersionUID = 100L;
#XmlElement(name = "addressLine1", required = true)
protected String addressLine1;
#XmlElement(name = "addressLine2", required = true)
protected String addressLine2;
//Setters and getters
}
Now when I generate the XML string with jaxb marshalling I want the expected result like this:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Employee xmlns="http://www.test.com">
<empId>124</empId>
<empName>name</empName>
<Address xmlns:ns2="http://www.w3.org/2000/09/xmldsig#">
<ns2:streetLine1 Id="line1"/>
<ns2:streetLine2 Id="Line2"/>
</Address>
</Request>
Please suggest. Thanks in Advance.
There are some problems with your JAXB classes, I think you have copy pasted and changed some names wrongly. The following elements inside #XMLType must be defined as #XMLElement.
#XmlType(name = "Request",propOrder = {
"header",
"body",
"signature"
})
Anyways assuming the classes are right. You will need 2 changes to generate XML that has elements referred in different namespace.
Move the namespace to package level using #XMLSchema. i.e Add package-info.java at the package level to specify the namespaces.
Provide Address element with its own namespace in Employee class. Each element if not in parent namespace, must be overridden at this level.
package-info.java
#XmlSchema(
namespace = "http://www.test.com",
elementFormDefault = XmlNsForm.QUALIFIED)
package int1.d;
import javax.xml.bind.annotation.*;
Employee.java
package int1.d;
import java.io.Serializable;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "Request",propOrder = {
"header",
"body",
"signature"
})
#XmlRootElement(name="Employee")
public class Employee
implements Serializable
{
private static final long serialVersionUID = 8293193254658211943L;
#XmlElement(name = "Header", required = true)
protected String empId;
#XmlElement(name = "Body", required = true)
protected String empName;
#XmlElement(name = "Address", namespace="http://www.w3.org/2000/09/xmldsig#", required = true )
protected Address address;
public String getEmpId() {
return empId;
}
public void setEmpId(String empId) {
this.empId = empId;
}
public String getEmpName() {
return empName;
}
public void setEmpName(String empName) {
this.empName = empName;
}
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
}
package-info.java
#XmlSchema(
namespace = "http://www.w3.org/2000/09/xmldsig#",
elementFormDefault=XmlNsForm.QUALIFIED )
package int1.d2;
import javax.xml.bind.annotation.*;
Address.java
package int1.d2;
import java.io.Serializable;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "Address", propOrder = {
"streetLine1",
"streetLine2",
})
#XmlRootElement(name="Address")
public class Address
implements Serializable
{
private final static long serialVersionUID = 100L;
#XmlElement(name = "addressLine1", required = true)
protected String addressLine1;
#XmlElement(name = "addressLine2", required = true)
protected String addressLine2;
public String getAddressLine1() {
return addressLine1;
}
public void setAddressLine1(String addressLine1) {
this.addressLine1 = addressLine1;
}
public String getAddressLine2() {
return addressLine2;
}
public void setAddressLine2(String addressLine2) {
this.addressLine2 = addressLine2;
}
}
output generated by JAXB
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Employee xmlns="http://www.test.com" xmlns:ns2="http://www.w3.org/2000/09/xmldsig#">
<Header>124</Header>
<Body>bae</Body>
<ns2:Address>
<ns2:addressLine1>line1</ns2:addressLine1>
<ns2:addressLine2>line2</ns2:addressLine2>
</ns2:Address>
</Employee>

Bug in org.eclipse.persistence.jaxb.compiler.SchemaGenerator with inheritance, #XmlAttribute and #XmlAnyAttribute?

The issues:
Is there a but in MOXy's SchemaGenerator with inheritance, #XmlAttribute and #XmlAnyAttribute?
If so, how can I assist in fixing it? And when would a fix be planned?
I have two classes:
One abstract class (AbstractKeyedItem) that may have an #XmlAttribute "key"
A concrete class (MyAnyAttr) that extends AbstractKeyedItem, has a #XmlAnyAttribute, and has an #XmlElement list of MyAnyAttr
The problem is that the default Oracle (Sun) XmlSchemaGenerator generates a valid XML Schema, but that the Eclipselink/MOXy SchemaGenerator doesn't seem to do so.
Eclipse reports on the invalid XSD:
s4s-elt-invalid-content.1: The content of 'myAnyAttr' is invalid. Element 'anyAttribute' is invalid, misplaced, or occurs too often.
xmllint reports:
Element '{http://www.w3.org/2001/XMLSchema}complexType': The content is not valid. Expected is (annotation?, (simpleContent | complexContent | ((group | all | choice | sequence)?, ((attribute | attributeGroup)*, anyAttribute?)))).
I think to have isolated the problem. I provide all (most) required resources.
XSD as generated by MOXy (xsd:anyAttribute is the offending element):
<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:complexType name="myAnyAttr">
<xsd:complexContent>
<xsd:extension base="abstractKeyedItem">
<xsd:sequence>
<xsd:element name="kid" type="myAnyAttr" minOccurs="0" maxOccurs="unbounded"/>
</xsd:sequence>
</xsd:extension>
</xsd:complexContent>
<xsd:anyAttribute processContents="skip" namespace="##other"/>
</xsd:complexType>
<xsd:complexType name="abstractKeyedItem" abstract="true">
<xsd:sequence/>
<xsd:attribute name="key" type="xsd:string"/>
</xsd:complexType>
<xsd:element name="my-any-attr-root" type="myAnyAttr"/>
</xsd:schema>
The XSD generated by Oracle:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<xs:schema version="1.0" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="my-any-attr-root" type="myAnyAttr"/>
<xs:complexType name="myAnyAttr">
<xs:complexContent>
<xs:extension base="abstractKeyedItem">
<xs:sequence>
<xs:element name="kid" type="myAnyAttr" minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
<xs:anyAttribute namespace="##other" processContents="skip"/>
</xs:extension>
</xs:complexContent>
</xs:complexType>
<xs:complexType name="abstractKeyedItem" abstract="true">
<xs:sequence/>
<xs:attribute name="key" type="xs:string"/>
</xs:complexType>
</xs:schema>
Abstract class:
package xml.anyattr;
import javax.xml.bind.annotation.XmlAttribute;
public abstract class AbstractKeyedItem {
#XmlAttribute
public String key;
public AbstractKeyedItem() {}
}
Concrete class:
package xml.anyattr;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAnyAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.namespace.QName;
#XmlRootElement(name = "my-any-attr-root")
#XmlAccessorType(XmlAccessType.FIELD)
public class MyAnyAttr extends AbstractKeyedItem {
#XmlAnyAttribute
public Map<QName, String> attrMap = new HashMap<QName, String>();
#XmlElement(name = "kid")
public List<MyAnyAttr> myAnyAttrKids = new ArrayList<MyAnyAttr>();
public MyAnyAttr() {}
}
Utilities used to generate files:
package xml.anyattr;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.PropertyException;
import javax.xml.bind.SchemaOutputResolver;
import javax.xml.namespace.QName;
import javax.xml.transform.Result;
import javax.xml.transform.stream.StreamResult;
import org.apache.pdfbox.io.IOUtils;
public class MyAnyAttrUtils {
private static class MySchemaOutputResolver extends SchemaOutputResolver {
#Override
public Result createOutput(String namespaceUri, String suggestedFileName) throws IOException {
new Throwable().printStackTrace(System.out);
File file = null;
if (namespaceUri.equals("")) {
file = XSD;
} else {
throw new IOException("Unsupported namespaceUri: " + namespaceUri);
}
StreamResult result = new StreamResult(file);
result.setSystemId(file.toURI().toURL().toString());
return result;
}
}
static File XSD = new File("target/test-classes/my-any-utils.xsd");
private static void generateXsd() throws JAXBException, IOException {
rm(XSD);
JAXBContext jaxbContext = JAXBContext.newInstance(MyAnyAttr.class);
SchemaOutputResolver outputResolver = new MySchemaOutputResolver();
jaxbContext.generateSchema(outputResolver);
InputStream is = new FileInputStream(XSD);
System.out.println("XSD:");
IOUtils.copy(is, System.out);
}
public static void main(String[] args) {
try {
printSimple();
generateXsd();
System.exit(0);
} catch (Exception e) {
e.printStackTrace(System.err);
System.exit(1);
}
}
private static void printSimple() throws JAXBException, PropertyException {
MyAnyAttr myAnyAttr = new MyAnyAttr();
myAnyAttr.key = "parent";
myAnyAttr.attrMap.put(new QName("oth", "dad"), "foo");
MyAnyAttr kid = new MyAnyAttr();
kid.key = "child";
kid.attrMap.put(new QName("oth", "kid"), "bar");
myAnyAttr.myAnyAttrKids.add(kid);
JAXBContext jaxbContext = JAXBContext.newInstance(MyAnyAttr.class);
Marshaller marshaller = jaxbContext.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
System.out.println("XML:");
marshaller.marshal(myAnyAttr, System.out);
System.out.println();
}
private static void rm(File file) throws IOException {
if (file.exists()) {
if (!file.delete()) {
throw new IOException("Failed to delete " + file);
}
}
}
}
Stack trace of Oracle implementation:
java.lang.Throwable
at xml.anyattr.MyAnyAttrUtils$MySchemaOutputResolver.createOutput(MyAnyAttrUtils.java:25)
at com.sun.xml.internal.bind.v2.schemagen.FoolProofResolver.createOutput(FoolProofResolver.java:55)
at com.sun.xml.internal.bind.v2.schemagen.XmlSchemaGenerator.write(XmlSchemaGenerator.java:462)
at com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl.generateSchema(JAXBContextImpl.java:794)
at xml.anyattr.MyAnyAttrUtils.generateXsd(MyAnyAttrUtils.java:44)
at xml.anyattr.MyAnyAttrUtils.main(MyAnyAttrUtils.java:53)
Stack trace of MOXy implementation:
java.lang.Throwable
at xml.anyattr.MyAnyAttrUtils$MySchemaOutputResolver.createOutput(MyAnyAttrUtils.java:25)
at org.eclipse.persistence.jaxb.compiler.SchemaGenerator.getSchemaForNamespace(SchemaGenerator.java:687)
at org.eclipse.persistence.jaxb.compiler.SchemaGenerator.addSchemaComponents(SchemaGenerator.java:177)
at org.eclipse.persistence.jaxb.compiler.SchemaGenerator.generateSchema(SchemaGenerator.java:154)
at org.eclipse.persistence.jaxb.compiler.SchemaGenerator.generateSchema(SchemaGenerator.java:142)
at org.eclipse.persistence.jaxb.compiler.Generator.generateSchemaFiles(Generator.java:221)
at org.eclipse.persistence.jaxb.JAXBContext.generateSchema(JAXBContext.java:405)
at org.eclipse.persistence.jaxb.JAXBContext.generateSchema(JAXBContext.java:353)
at xml.anyattr.MyAnyAttrUtils.generateXsd(MyAnyAttrUtils.java:44)
at xml.anyattr.MyAnyAttrUtils.main(MyAnyAttrUtils.java:53)

How to change a specific type's element name globally?

Let's say there is a class named
// with respect.
public class BlaiseDoughan {
}
I know I can change the element's name like this.
#XmlRootElement
public class MyRoot {
#XmlElement(name = "blaise-doughan") // I want this
private BlaiseDoughan blaiseDoughan
}
Is there any way to permanently set the target element name of BlaiseDoughan to blaise-doughan in every or any occurrence without name attribute?
I mean
#XmlRootElement
public class SomeOtherRoot {
#XmlElement // without the [name = "blaise-doughan"] part?
private BlaiseDoughan blaiseDoughan
}
Is there any package-level technique for this?
You could do:
Java Model
BlaiseDoughan
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement(name="blaise-doughan")
public class BlaiseDoughan {
}
MyRoot
And then every reference to it could be mapped with #XmlElementRef.
import javax.xml.bind.annotation.*;
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class MyRoot {
#XmlElementRef
private BlaiseDoughan blaiseDoughan;
public void setBlaiseDoughan(BlaiseDoughan blaiseDoughan) {
this.blaiseDoughan = blaiseDoughan;
}
}
Demo Code
Demo
import javax.xml.bind.*;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(MyRoot.class);
MyRoot myRoot = new MyRoot();
myRoot.setBlaiseDoughan(new BlaiseDoughan());
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(myRoot, System.out);
}
}
Output
<?xml version="1.0" encoding="UTF-8"?>
<myRoot>
<blaise-doughan/>
</myRoot>
Why This Works
#XmlElementRef corresponds to using ref in the element definition:
<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<xsd:complexType name="blaiseDoughan"/>
<xsd:complexType name="myRoot">
<xsd:sequence>
<xsd:element ref="blaise-doughan"/>
</xsd:sequence>
</xsd:complexType>
<xsd:element name="myRoot" type="myRoot"/>
<xsd:element name="blaise-doughan" type="blaiseDoughan"/>
</xsd:schema>

jaxb marshall Boolean as Integer (0,1) problems

My problem seems pretty simple, yet I was unable to find anything exactly like it on stackoverflow.
I'm using jaxb to marshall/unmarshall this object:
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "")
#XmlRootElement(name = "root")
public class MyJaxbObject implements Serializable
{
#XmlElement(name = "DELETE")
#XmlJavaTypeAdapter(BooleanIntAdapter.class)
private Boolean delete;
#XmlElement(name = "message")
private String message;
constructors.. getters... setters...
}
My BooleanAdapter is a simple XmlAdapter<Integer, Boolean> that turns true/false to 1/0 and back.
Unmarshalling works, but marshalling does not. it always yeilds this:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<root>
<DELETE xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.or/2001/XMLSchema" xsi:type="xs:boolean">true</DELETE>
<message>***DONE***</message>
</root>
When I change the xml element config to #XmlElement(name = "DELETE",type = Boolean.class) unmarshalling of the boolean fails and marshalling yields this:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<root>
<DELETE xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xs="http://www.w3.org/2001/XMLSchema" xsi:type="xs:int">1</DELETE>
<message>***DONE***</message>
</root>
I put simple print messages in the marshal/unmarshal methods of the xml adapter and tried to marshal/unmarshal this kind of object.
I saw that without type declaration unmarshal method is called but marshal is not.
With the type declaration only marshal is called.
Help??
How can I marshal/unmarshal my Boolean to/from {1,0} and possibly get rid of the xsi:type in the marshalled xml?
Edit - this is the code i used to test marshal/unmarshal:
DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance();
JAXBContext context = javax.xml.bind.JAXBContext.newInstance("my.package.classes");
Unmarshaller unmarshal = context.createUnmarshaller();
Marshaller marshal = context.createMarshaller();
marshal.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
String str = "<root><DELETE>1</DELETE><message>***DONE***</message></root>";
DocumentBuilder builder = docBuilderFactory.newDocumentBuilder();
Document d = null;
d = builder.parse(new InputSource(new StringReader(str)));
MyJaxbObject myJaxUnmarsh = unmarshal.unmarshal(d.getFirstChild(), MyJaxbObject.class).getValue();
System.out.println(myJaxUnmarsh.getMessage() + " , " + myJaxUnmarsh.getDelete());
MyJaxbObject myJax = new MyJaxbObject();
myJax.setDelete(true);
myJax.setMessage("***DONE***");
marshal.marshal(myJax, System.out);
With the following implementation of BooleanIntAdapter:
BooleanIntAdapter
package forum9380680;
import javax.xml.bind.annotation.adapters.XmlAdapter;
public class BooleanIntAdapter extends XmlAdapter<Integer, Boolean> {
#Override
public Boolean unmarshal(Integer v) throws Exception {
return v.equals(1);
}
#Override
public Integer marshal(Boolean v) throws Exception {
if(v) {
return 1;
} else {
return 0;
}
}
}
Output
I get the following output:
<?xml version="1.0" encoding="UTF-8"?>
<root>
<DELETE>1</DELETE>
<message>***DONE***</message>
</root>
Below is the rest of the code I used:
Demo
package forum9380680;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(MyJaxbObject.class);
MyJaxbObject object = new MyJaxbObject();
object.setDelete(true);
object.setMessage("***DONE***");
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(object, System.out);
}
}
MyJaxbObject
package forum9380680;
import java.io.Serializable;
import javax.xml.bind.annotation.*;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "")
#XmlRootElement(name = "root")
public class MyJaxbObject implements Serializable
{
#XmlElement(name = "DELETE")
#XmlJavaTypeAdapter(BooleanIntAdapter.class)
private Boolean delete;
#XmlElement(name = "message")
private String message;
public Boolean getDelete() {
return delete;
}
public void setDelete(Boolean delete) {
this.delete = delete;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
found the problem:
CXF pom makes the project use jaxb-impl version 2.1.0.
Without CXF the project uses the JDK default which was 2.1.10 in my case.
see:
http://jaxb.java.net/guide/Which_JAXB_RI_is_included_in_which_JDK_.html
I added the following under dependency management to fix the problem
<dependency>
<groupId>com.sun.xml.bind</groupId>
<artifactId>jaxb-impl</artifactId>
<version>2.2.5</version>
<type>jar</type>
<scope>compile</scope>
</dependency>

Jaxb: xs:attribute null values

Reg: Jaxb
I'm basically trying to set up a role in JAXB which says that whenever an null field is encountered, instead of ignoring it in the output, set it to an empty value.
For xmlElement I got answer like we need to use nillable="true" but for how we need to set the null value. by googling I found that we need to use use="optional" but its not working in my case.
My xsd's part is below:
<xs:attribute name="RomVersion" type="xs:string" use="required" />
<xs:attribute name="MACAddress" type="xs:string" use="required" />
<xs:attribute name="LargestFreeBlock" type="xs:unsignedInt" use="required" />
<xs:attribute name="TimeSinceLastReset" type="xs:unsignedInt" use="optional" />
<xs:attribute name="ResetReason" type="xs:string" use="optional" />
<xs:attribute name="TimeStamp" type="xs:unsignedInt" use="optional" />
<xs:attribute name="ECOList" type="xs:string" use="optional" />
</xs:complexType>
</xs:element>
Please give me the solution ASAP if anyone knows.
Starting from XML Schema
In a previous answer I described how to solve your use case when starting from Java objects. Based on your comments to that answer, this answer describes how the same thing can be done when the model is generated from an XML schema.
XML Schema (attributeAdapter.xsd)
For this example we will use the following XML schema:
<?xml version="1.0" encoding="utf-8" ?>
<xs:schema
elementFormDefault="qualified"
targetNamespace="http://www.example.com/adapter"
xmlns:nytd="http://www.example.com/adapter"
xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="root">
<xs:complexType>
<xs:attribute name="foo" type="xs:string"/>
<xs:attribute name="bar" type="xs:string"/>
</xs:complexType>
</xs:element>
</xs:schema>
StringConverter
We will need to define a class to do our special String handling. For this use case we want a null field/property value to be treated as empty String ("") in the XML document:
package com.example.adapter;
public class StringConverter {
public static String parseString(String value) {
if("".equals(value)) {
return null;
}
return value;
}
public static String printString(String value) {
if(null == value) {
return "";
}
return value;
}
}
Binding File (attributeAdapterBinding.xml)
We will need to use a JAXB binding file to customize the class generation. The binding file below will allow us to leverage the StringConverter class that we defined above:
<jaxb:bindings
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
version="2.1">
<jaxb:bindings schemaLocation="attributeAdapter.xsd">
<jaxb:bindings node="//xs:element[#name='root']/xs:complexType">
<jaxb:bindings node="xs:attribute[#name='foo']">
<jaxb:property>
<jaxb:baseType>
<jaxb:javaType name="java.lang.String"
parseMethod="com.example.adapter.StringConverter.parseString"
printMethod="com.example.adapter.StringConverter.printString"/>
</jaxb:baseType>
</jaxb:property>
</jaxb:bindings>
<jaxb:bindings node="xs:attribute[#name='bar']">
<jaxb:property>
<jaxb:baseType>
<jaxb:javaType name="java.lang.String"
parseMethod="com.example.adapter.StringConverter.parseString"
printMethod="com.example.adapter.StringConverter.printString"/>
</jaxb:baseType>
</jaxb:property>
</jaxb:bindings>
</jaxb:bindings>
</jaxb:bindings>
</jaxb:bindings>
XJC call
We will make our XJC call as follows:
xjc -d out -b attributeAdapterBinding.xml attributeAdapter.xsd
Domain Model (Root)
The fields/properties that we customized in the binding file will be annotated with #XmlJavaTypeAdapter;
package com.example.adapter;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "")
#XmlRootElement(name = "root")
public class Root {
#XmlAttribute
#XmlJavaTypeAdapter(Adapter1 .class)
protected String foo;
#XmlAttribute
#XmlJavaTypeAdapter(Adapter2 .class)
protected String bar;
public String getFoo() {
return foo;
}
public void setFoo(String value) {
this.foo = value;
}
public String getBar() {
return bar;
}
public void setBar(String value) {
this.bar = value;
}
}
XmlAdapter (Adapter1)
The generated XmlAdapter class will look something like the following. Note how it leverages our StringConverter class:
package com.example.adapter;
import javax.xml.bind.annotation.adapters.XmlAdapter;
public class Adapter1 extends XmlAdapter<String, String> {
public String unmarshal(String value) {
return (com.example.adapter.StringConverter.parseString(value));
}
public String marshal(String value) {
return (com.example.adapter.StringConverter.printString(value));
}
}
Demo
Now if we run the following demo code:
package com.example.adapter;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(Root.class);
Root root = new Root();
root.setFoo(null);
root.setBar(null);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(root, System.out);
}
}
Output
We will get the desired output:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<root xmlns="http://www.example.com/adapter" foo="" bar=""/>
UPDATE (Alternate Binding File)
Alternatively, if you wanted the adapter applied to all properties of type xsd:string then you could use an binding file that looked something like;
<jaxb:bindings
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
version="2.1">
<jaxb:globalBindings>
<jaxb:javaType
name="String"
xmlType="xs:string"
parseMethod="com.example.adapter.StringConverter.parseString"
printMethod="com.example.adapter.StringConverter.printString"/>
</jaxb:globalBindings>
</jaxb:bindings>
Starting from Java Objects
For fields/properties mapped as #XmlAttribute, a JAXB implementation (Metro, MOXy, JaxMe, etc) will marshal an empty String ("") value as property="". You can use an XmlAdapter to expose your null values as empty Strings to get the desired behaviour:
NullStringAdapter
import javax.xml.bind.annotation.adapters.XmlAdapter;
public class NullStringAdapter extends XmlAdapter<String, String> {
#Override
public String unmarshal(String v) throws Exception {
if("".equals(v)) {
return null;
}
return v;
}
#Override
public String marshal(String v) throws Exception {
if(null == v) {
return "";
}
return v;
}
}
Root
The following is how you specify the adapter in your domain model. The same adapter can be used on many properties:
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
#XmlRootElement
public class Root {
private String foo;
private String bar;
#XmlAttribute
#XmlJavaTypeAdapter(NullStringAdapter.class)
public String getFoo() {
return foo;
}
public void setFoo(String foo) {
this.foo = foo;
}
#XmlAttribute
#XmlJavaTypeAdapter(NullStringAdapter.class)
public String getBar() {
return bar;
}
public void setBar(String bar) {
this.bar = bar;
}
}
Demo
You can demonstrate the concept, by running the following demo code:
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(Root.class);
Root root = new Root();
root.setFoo(null);
root.setBar(null);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(root, System.out);
}
}
Output
The following is the demo code output:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<root bar="" foo=""/>
For More Information on JAXB's XmlAdapter See:
http://bdoughan.blogspot.com/2010/07/xmladapter-jaxbs-secret-weapon.html
http://bdoughan.blogspot.com/2010/12/jaxb-and-immutable-objects.html
http://bdoughan.blogspot.com/2010/12/represent-string-values-as-element.html
You may use default values plugin for that.
Please look that question: JAXB xjc: How to generate code for Strings that returns empty if the value is null?

Resources