I have an element in my XML Schema that is defined as follows:
<xs:complexType name="MyNumberCodeType">
<xs:sequence>
<xs:element name="Code" type="NumberCodeValueType" maxOccurs="unbounded" />
</xs:sequence>
</xs:complexType>
Where NumberCodeValueType is:
<xs:simpleType name="NumberCodeValueType">
<xs:restriction base="xs:int">
<xs:pattern value="[0-7]{7}"/>
</xs:restriction>
</xs:simpleType>
That is, my number can start with leading 0s. I can NOT modify this schema. I am using JAXB to generate my Java classes. Unfortunately, the accessor for the Code
element takes a list of integers as the argument which means all leading 0s are stripped off (because, from what I can tell, there's no way to keep leading 0s in Java when using an integer type)!
Is there any way I can fix this?
Thanks for your help!
After the Java artifacts for your application are generated, you can generate fully annotated Java classes from an XML schema file by using the JAXB schema compiler, xjc command-line tool.
The @XmlType annotation can be defined for a class. The annotation element propOrder() in the @XmlType annotation allows you to specify the content order in the generated schema type. When you use the @XmlType.
JAXB definitionsMarshalling is the process of transforming Java objects into XML documents. Unmarshalling is the process of reading XML documents into Java objects. The JAXBContext class provides the client's entry point to the JAXB API.
When a top level class or an enum type is annotated with the @XmlRootElement annotation, then its value is represented as XML element in an XML document. This annotation can be used with the following annotations: XmlType , XmlEnum , XmlAccessorType , XmlAccessorOrder .
You could do the following:
NumberFormatter
You can do this by writing your own formatter:
package forum7182533;
public class NumberFormatter {
public static String printInt(Integer value) {
String result = String.valueOf(value);
for(int x=0, length = 7 - result.length(); x<length; x++) {
result = "0" + result;
}
return result;
}
public static Integer parseInt(String value) {
return Integer.valueOf(value);
}
}
XMLSchema (format.xsd)
Then when you are going to generate your classes from your XML Schema:
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="root">
<xs:complexType>
<xs:sequence>
<xs:element name="number" type="NumberCodeValueType" />
</xs:sequence>
</xs:complexType>
</xs:element>
<xs:simpleType name="NumberCodeValueType">
<xs:restriction base="xs:int">
<xs:pattern value="[0-7]{7}" />
</xs:restriction>
</xs:simpleType>
</xs:schema>
bindings.xml
You will leverage a JAXB bindings file to reference your formatter:
<jxb:bindings xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:jxb="http://java.sun.com/xml/ns/jaxb" version="2.1">
<jxb:bindings schemaLocation="format.xsd">
<!--jxb:bindings node="//xs:simpleType[@name='NumberCodeValueType']" -->
<jxb:bindings node="//xs:element[@name='number']">
<jxb:property>
<jxb:baseType>
<jxb:javaType name="java.lang.Integer"
parseMethod="forum7182533.NumberFormatter.parseInt" printMethod="forum7182533.NumberFormatter.printInt" />
</jxb:baseType>
</jxb:property>
</jxb:bindings>
</jxb:bindings>
</jxb:bindings>
XJC Call
The bindings file is referenced in the XJC call as:
xjc -d out -p forum7182533 -b bindings.xml format.xsd
Adapter1
This will cause an XmlAdapter
to be created that leverages your formatter:
package forum7182533;
import javax.xml.bind.annotation.adapters.XmlAdapter;
public class Adapter1
extends XmlAdapter<String, Integer>
{
public Integer unmarshal(String value) {
return (forum7182533.NumberFormatter.parseInt(value));
}
public String marshal(Integer value) {
return (forum7182533.NumberFormatter.printInt(value));
}
}
Root
The XmlAdapter
will be referenced from your domain object using the @XmlJavaTypeAdapter
annotation:
package forum7182533;
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;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
@XmlAccessorType(XmlAccessType.FIELD)
@XmlType(name = "", propOrder = {
"number"
})
@XmlRootElement(name = "root")
public class Root {
@XmlElement(required = true, type = String.class)
@XmlJavaTypeAdapter(Adapter1 .class)
protected Integer number;
public Integer getNumber() {
return number;
}
public void setNumber(Integer value) {
this.number = value;
}
}
Demo
Now if you run the following demo code:
package forum7182533;
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.setNumber(4);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(root, System.out);
}
}
Output
You will get the desired output:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<root>
<number>0000004</number>
</root>
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With