I have an empty tag like this <tagName/>. When I unmarshalling it if this property is the type of long or float it is null. But if this property is the type of string, the property is tagName = '';. And after marshalling is <tagName></tagName>. How can I set empty tag name which is string java property to null while unmarshalling?
There are (at least) 2 ways to do this.
If the classes are yourself and not auto-generated from xsd or similar you can use an adapter.
For example a class Cart:
#XmlRootElement(name = "Cart")
#XmlAccessorType(XmlAccessType.FIELD)
public class Cart {
#XmlJavaTypeAdapter(EmptyTagAdapter.class)
protected String tagName;
}
can use an adapter like below:
public class EmptyTagAdapter extends XmlAdapter<String, String> {
#Override
public String marshal(String arg0) throws Exception {
return arg0;
}
#Override
public String unmarshal(String arg0) throws Exception {
if(arg0.isEmpty()) {
return null;
}
return arg0;
}
}
For an xml that looks like this:
<Cart>
<tagName/>
</Cart>
You would get the empty tagName as null.
If your classes are generated from an xsd you could mention that the field can be nillable.
For example as below:
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" version="2.1">
<xs:element name="Cart">
<xs:complexType>
<xs:all>
<xs:element name="tagName" type="xs:string" nillable="true" />
</xs:all>
</xs:complexType>
</xs:element>
</xs:schema>
and then you would need to have in your xml with the empty element xsi:nil="true" as this example:
<Cart xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<tagName/>
<tagName xsi:nil="true" />
</Cart>
It would have the same result, the value as null.
The use of the adapter is more to my liking but depends on your case. Hopefully one of the cases covers you.
Related
I am generating code from an XSD using JAXB. I have an external bindings file that defines the implementation type for one of the XSD types (using the class tag/implClass attribute). When I do this, the generated ObjectFactory is modified to return an instance of the specified implementing class. However, the generated classes still declare members with the generated underlying type. Is there some way to make all uses of the generated XSD type reference my implementation type instead?
As an example, assume "example.xsd" is as follows:
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema" ...>
<xsd:element name="Root">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="Member" type="MemberType" maxOccurs="unbounded" />
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:complexType name="MemberType" />
</xsd:schema>
Then, I have the following "bindings.xjb" file:
<bindings xmlns="http://java.sun.com/xml/ns/jaxb"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
schemaLocation="example.xsd" node="/xsd:schema" version="2.1">
<bindings node="./xsd:complexType[#name='MemberType']">
<class implClass="myNamespace.Member" />
</bindings>
</bindings>
After running xjc to generate JAXB classes in the above scenario, I get an ObjectFactory class that includes the following method:
public MemberType createMemberType() {
return new Member();
}
So the factory is correctly generating an instance of my implementation for MemberType. However, the implementation of the generated Root class includes:
protected List<MemberType> member;
public List<MemberType> getMember() {
if (member == null) {
member = new ArrayList<MemberType>();
}
return this.member;
}
I would instead like the implementation to be:
protected List<Member> member;
public List<Member> getMember() {
if (member == null) {
member = new ArrayList<Member>();
}
return this.member;
}
Is there a way to specify that I want to replace MemberType with myNamespace.Member within "bingings.xjb"? I would expect the result of ObjectFactory.createMemberType to change as well due to this configuration. Thanks.
After much trial and error, I finally discovered a way to do this. The following is the working "bindings.xjb" file:
<bindings xmlns="http://java.sun.com/xml/ns/jaxb"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
schemaLocation="example.xsd" node="/xsd:schema" version="2.1">
<bindings node="./xsd:complexType[#name='MemberType']">
<class implClass="myNamespace.Member" />
</bindings>
<bindings node="//xsd:element[#name='Member']">
<property name="Members">
<baseType name="myNamespace.Member" />
</property>
</bindings>
</bindings>
The generated ObjectFactory.createMemberType method is unchanged:
public MemberType createMemberType() {
return new Member();
}
However, the generated Root class now has the following implementation:
protected List<myNamespace.Member> members;
public List<myNamespace.Member> getMembers() {
if (members == null) {
members = new ArrayList<myNamespace.Member>();
}
return this.members;
}
I have verified that the resulting JAXB objects are both marshalled and unmarshalled correctly.
I have a very simple class that I want to transmit as XML. The accepted XML format is a list of fields made of name attribute and sequence of string values. Can I annotate my class so that I can:
Use class name as attribute "type" of xml entity
Use class fields names as attribute "name" in xml sequence of Fields ?
What would be the recommended way? The example class in question:
class MyEntityType {
public List<String> myField1; // = {"A", "B"}
public List<String> myField2; // = {"C", "D"}
}
in xml format:
<Entity type="MyEntityType">
<Fields>
<Field name="myField1">
<Value>A</Value>
<Value>B</Value
</Field>
<Field name="myField2">
<Value>C</Value>
<Value>D</Value>
</Field>
</Fields>
</Entity>
What I would like to avoid is having to declare a Field class, and put a list of them in my object, because I want to enforce a particular set of required fields.
class MyEntityType {
public static class Field {
String name;
String values
}
public List<Fields> fields;
}
For completeness these are supported schemas:
<xs:complexType name="EntityComplexType" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:sequence>
<xs:element name="Fields" type="FieldsComplexType" />
</xs:sequence>
<xs:attribute name="Type" type="xs:string" use="required" />
</xs:complexType>
<xs:complexType name="FieldsComplexType" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:sequence>
<xs:element name="Field" type="FieldComplexType" maxOccurs="unbounded" />
</xs:sequence>
</xs:complexType>
<xs:complexType name="FieldComplexType" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:sequence>
<xs:element name="Value" minOccurs="0" maxOccurs="unbounded">
<xs:complexType>
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:attribute name="Alias" type="xs:string" use="optional" />
<xs:attribute name="ReferenceValue" type="xs:string" use="optional" />
</xs:extension>
</xs:simpleContent>
</xs:complexType>
</xs:element>
</xs:sequence>
<xs:attribute name="Name" use="required" />
</xs:complexType>
I suppose that you realize that what you want is a significant deviation from XML's standard procedure, ignoring the concepts underlying the design of this data format, and the Java Architecture for XML Binding as well. Thus, class fields are meant to be represented by element names. Also, using an XML structure that does not reflect the structure of the data (class MyEntityType) or, vice versa, using a class that does not correspond to the structure of the data creates a gap that no out-of-the-box tool can handle. There are neither annotations nor external bindings to achieve this completely different structure.
There is, of course, the JAXB feature of adapter, which helps to replace one Java type by another, but here one has to replace the entire Java structure before it can be marshalled into XML.
Your XML schema (with a small correction) generates the required Java classes EntityComplexType, FieldsComplexType and FieldComplexType (which I don't paste here).
A Java class EntityAdapter can be written in the spirit of an adapter:
public class EntityAdapter {
public MyEntityType unmarshal(EntityComplexType v){
// ...
return new MyEntityType();
}
public EntityComplexType marshal(MyEntityType v){
EntityComplexType ect = new EntityComplexType();
ect.setType( v.getClass().getSimpleName() );
FieldsComplexType fct = new FieldsComplexType();
ect.setFields( fct );
FieldComplexType field1 = new FieldComplexType();
fct.getField().add( field1 );
field1.setName( "myField1" );
for( String s: v.getMyField1() ){
field1.getValue().add( s );
}
FieldComplexType field2 = new FieldComplexType();
fct.getField().add( field2 );
field2.setName( "myField2" );
for( String s: v.getMyField2() ){
field2.getValue().add( s );
}
return ect;
}
}
And marshalling proceeds as usual, with the addition of transforming the MyEntityType object to an EntityComplexType object:
MyEntityType met = ...;
EntityAdapter adapter = new EntityAdapter();
EntityComplexType ect = adapter.marshal( met );
ObjectFactory of = new ObjectFactory();
JAXBElement<EntityComplexType> jbe = of.createEntityComplexType( ect );
JAXBContext jc = JAXBContext.newInstance( PACKAGE );
Marshaller m = jc.createMarshaller();
m.marshal( jbe, ... );
I've got the following xsd tag:
<xs:complexType name="documentation">
<xs:simpleContent>
<xs:extension base="xs:string">
<xs:attribute type="xs:string" name="language" use="required"/>
</xs:extension>
</xs:simpleContent>
this generates (with jax-b):
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "documentation", propOrder = {
"value"
})
public class Documentation {
#XmlValue
protected String value;
#XmlAttribute(name = "language", required = true)
protected String language;
And I want some output like:
<documentation language="NL">SomeValue</documentation>
but Xstream generates:
<documentation language="NL">
<value>SomeValue</value>
</documentation>
how could I remove the value tags? I don't want them..
Code to generate the xml tags (this is just a snippet..):
private void createDocumentation(Description description, String docNL) {
List<Documentation> documentations = description.getDocumentation();
Documentation documentationNL = new Documentation();
documentationNL.setLanguage("NL");
documentationNL.setValue(docNL);
documentations.add(documentationNL);
}
private void createXmlFile(Description description) {
XStream xstream = new XStream(new DomDriver());
xstream.alias("description", Description.class);
xstream.alias("documentation", Documentation.class);
xstream.addImplicitCollection(Description.class, "documentation");
xstream.useAttributeFor(Documentation.class, "language");
String xml = xstream.toXML(description);
}
XStream provides a standard converter implementation called ToAttributedValueConverter that you can wire in for any simple-content-plus-attributes type like this:
#XStreamConverter(value = ToAttributedValueConverter.class, strings = { "value" })
public class Documentation {
protected String value;
protected String language;
}
The strings annotation element names the property that corresponds to the element content, all other properties will become attributes. If you want to declare the converter using xstream.registerConverter instead of using XStream annotations then you use
xstream.registerConverter(new ToAttributedValueConverter(Documentation.class,
xstream.getMapper(), xstream.getReflectionProvider(), xstream.getConverterLookup(),
"value"));
(the Mapper, ReflectionProvider and ConverterLookup objects get supplied to the converter automatically when you register it using annotations, but must be provided explicitly for registerConverter).
One option is to create a custom converter for your Documentation object.
Take a look at the XStream Converter tutorial
EDIT TS:
adding:
xstream.registerConverter(new DocumentationConverter());
and
public class DocumentationConverter implements Converter {
public boolean canConvert(Class clazz) {
return clazz.equals(Documentation.class);
}
public void marshal(Object value, HierarchicalStreamWriter writer,
MarshallingContext context) {
Documentation documentation = (Documentation) value;
writer.addAttribute("language", documentation.getLanguage());
writer.setValue(documentation.getValue());
}
public Object unmarshal(HierarchicalStreamReader reader,
UnmarshallingContext context) {
Documentation documentation = new Documentation();
reader.moveDown();
documentation.setLanguage(reader.getAttribute("language"));
documentation.setValue(reader.getValue());
reader.moveUp();
return documentation;
}
}
did the job
for the request for my web service, I wanted to differ between requested null value and missing tag. In other words I needed the following element definition:
<xs:element minOccurs="0" name="minzeronil" nillable="true" type="xs:string"/>
I developed the web service code-first, so I defined the element using JAXBElementRef:
#XmlRegistry
public class ObjectFactory {
#XmlElementDecl(name = "minzeronil", namespace = XmlNamespace.MY_SERVICE)
public JAXBElement<String> createMinzeronil(final String value) {
return new JAXBElement<String>(new QName(XmlNamespace.MY_SERVICE, "minzeronil"), String.class, value);
}
}
Now, I expected to see nillable = "true" in the definition of the element. Instead, I got:
<xs:element name="minzeronil" type="xs:string"/>
<xs:element ref="tns:minzeronil" minOccurs="0"/>
How can I generate nillable = "true" from my java code? ... and still use JAXBElement in my code and its methods like isNil() ...
UPDATE: I deploy the code on glassfish, so glassfish is the one that generates the wsdl and xsd.
use #XmlElement(nillable = true) in your Java Class
#XmlElement(nillable=true)
public String getAString() {
return AString;
}
Refer to this Stack Overflow question/answer
One of my client to integrate provide an XML with attribute name "_1", "_2" ... etc.
e.g.
<element _1="attr1" _2="attr2">
using JAXB to generate the class, the getter method of the attribute will be get1() and get2()
However in my JSP pages, using JSTL and EL, sure I cannot access the value through
${variable.1}
How can I access the value using EL correctly?
You could use an external binding file to rename the property generate by JAXB:
schema.xsd
Below is a sample XML schema based on your post:
<?xml version="1.0" encoding="UTF-8"?>
<schema
xmlns="http://www.w3.org/2001/XMLSchema"
targetNamespace="http://www.example.org"
xmlns:tns="http://www.example.org"
elementFormDefault="qualified">
<element name="element1">
<complexType>
<attribute name="_1" type="string" />
<attribute name="_2" type="string" />
</complexType>
</element>
</schema>
binding.xml
An external binding file is used to customize how Java classes are generated from the XML schema. Below we'll use an external binding file to rename the generated properties.
<jaxb:bindings
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:jaxb="http://java.sun.com/xml/ns/jaxb"
version="2.1">
<jaxb:bindings schemaLocation="schema.xsd">
<jaxb:bindings node="//xsd:attribute[#name='_1']">
<jaxb:property name="one"/>
</jaxb:bindings>
<jaxb:bindings node="//xsd:attribute[#name='_2']">
<jaxb:property name="two"/>
</jaxb:bindings>
</jaxb:bindings>
</jaxb:bindings>
XJC Call
Below is an example of how you reference the binding file when using the XJC tool.
xjc -b binding.xml schema.xsd
Element1
Below is what the generated class will look like:
package forum12259754;
import javax.xml.bind.annotation.*;
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "")
#XmlRootElement(name = "element1")
public class Element1 {
#XmlAttribute(name = "_1")
protected String one;
#XmlAttribute(name = "_2")
protected String two;
public String getOne() {
return one;
}
public void setOne(String value) {
this.one = value;
}
public String getTwo() {
return two;
}
public void setTwo(String value) {
this.two = value;
}
}
Use this notation:
${variable.["1"]}