Jaxb: xs: null attribute values

Reg: Jaxb

I'm basically trying to set up a role in JAXB, which says that whenever a null field is encountered, instead of ignoring it in the output, set it to an empty value.

For xmlElement, I got the answer as if we needed to use nillable = "true", but for how we needed to set the value to zero. by googling I found that we need to use use = "optional", but this does not work in my case.

My xsd 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 a solution as soon as possible if anyone knows.

+6
source share
3 answers

Starting with XML Schema

In a previous answer, I described how to solve your use case, starting with Java objects. Based on your comments on this answer, this answer describes how the same can be done when a model is created from an XML schema.

XML Schema (attributeAdapter.xsd)

In 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 perform special String processing. For this use case, we want the null / property value to be treated as an 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 the JAXB binding file to configure the generation of the class. The binding file below will allow us to use 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 configured in the binding file will be annotated using @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 this: Notice how it uses 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); } } 

Exit

We will get the desired result:

 <?xml version="1.0" encoding="UTF-8" standalone="yes"?> <root xmlns="http://www.example.com/adapter" foo="" bar=""/> 

UPDATE (alternative bind file)

Alternatively, if you want the adapter to be applied to all properties like xsd:string , then you could use a binding file that looked something like this:

 <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> 
+6
source

Starting with Java Objects

For fields / properties displayed as @XmlAttribute , a JAXB implementation (Metro, MOXy, JaxMe, etc.) will march on an empty String ("") value as property="" . You can use the XmlAdapter to output your null values ​​as empty strings to get the desired behavior:

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 a description of how you specify the adapter in your domain model. The same adapter can be used in 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); } } 

Exit

Below is the output of the demo code:

 <?xml version="1.0" encoding="UTF-8" standalone="yes"?> <root bar="" foo=""/> 

For more information on JAXB XmlAdapter, see

+5
source

You can use the default plugin for this.

Please look at this question: JAXB xjc: How to generate code for strings that returns an empty value if the value is zero?

0
source

Source: https://habr.com/ru/post/888020/


All Articles