JAXB -field based on two sibling XML elements - jaxb

for example i have this xml:
<xml>
<a>1</a>
<b>2</b>
</xml>
and this class:
#XmlRootElement(name = "xml")
public class xml{
int aPlusb;
....
}
i know how to create an XmlAdapter but i would like it to set the filed aPlusb to be the plus between the value of element a and the value of filed b.
is there a way to do this in JAXB without making an XmlTransient field and calculate it separately?

Related

How do I remove an XML layer using Jaxb

I have an XML file that looks like this
<coordinate>
<url>http://some-url</url>
<properties>
<property type="integer">key1=12345</property>
<property visibility="private" type="string">key2=value2</property>
</properties>
</coordinate>
I would like that to generate an Object structure that looks like this:
class Coordinate
string url
List<Property> properties
class Property
string type
string visibility
Jaxb seems to require a "Properties" type layer in between the coordinate element and the property elements. Is there any way to just get it to add the properties directly to the list contained in the Coordinate object?
JAXB #XmlElementWrapper annotation can be used for this scenario as below.
#XmlElementWrapper(name = "properties")
#XmlElement(name="property")
protected List<Property> propertyList = new ArrayList<Property>();

jxpath not honoring JAXB's XmlElement name of xjc-generated classes

I use an XML Schema Definition and JAXB to generate Java classes with proper #XmlElement or #XmlRootElement annotations.
Since the schema has some deep nesting in it (not my choice), I'd rather use jxpath to access deeply buried classes using an XPath (rather than cumbersome daisy-chain of .getThat() and that != null).
The problem is that some of the XML element names contain dashes, e.g. foo-bar. When I try to access elements using org.apache.jxpath, I need to rewrite my XPath so that such names are camel-cased instead (fooBar) like the name of the actual Java objects. Is there any way to tell jxpath to find the elements using the XPath corresponding to the XML element names (instead of the camel-cased Bean names)?
I think it is related to this question, however in my case I don't actually case what kind of tricks and decorations are used on the auto-generated classes, as long as xjc can do it.
Here is a simple example to illustrate the issue.
First, a small XSD file:
<?xml version="1.0" encoding="UTF-8"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema" elementFormDefault="qualified">
<xs:element name="record">
<xs:complexType>
<xs:sequence>
<xs:element name="foo-bar" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:element>
</xs:schema>
Compile it...
xjc -p org.pd.jx example.xsd
Here is the xjc-generated Record.java class (minus comments):
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "", propOrder = {"fooBar"})
#XmlRootElement(name = "record")
public class Record {
#XmlElement(name = "foo-bar", required = true)
protected String fooBar;
public String getFooBar() {return fooBar;}
public void setFooBar(String value) {this.fooBar = value;}
}
Then, trying to access the data via jxpath (in practice I have to deal with lots of deeply nested classes), one can see below that the correct XPath ("foo-bar") doesn't work, but a camel-cased version does.
Record record = new Record();
record.setFooBar("hello world");
JXPathContext context = JXPathContext.newContext(record);
context.setLenient(true);
String a = (String)context.getValue("foo-bar", String.class); // is null
String b = (String)context.getValue("fooBar", String.class); // "hello world"
I believe JXPath operates on an objects properties and not the XML elements they correspond to. I do not believe that JXPath parses any of the JAXB metadata so it wouldn't know the XML nodea you have mapped. What you are seeing appears to be the expected behaviour.

JAXB xjc: How to generate code for Strings that returns empty if the value is null?

Given the following example xsd snippet:
< xs:attribute name="SEGMENT" default="" use="optional" type="xs:string"/ >
when xjc generates the class containing the SEGMENT bean attribute, the following getter is auto-generated:
public String getSEGMENT() {
if (segment == null) {
return "";
} else {
return segment;
}
}
My question is how do you get it do the same for xs:element objects? In other words, given the following xsd snippet:
< xs:element name="NAME" default="" type="xs:string"/ >
I want to know if I can get xjc to generate the following:
public String getNAME() {
if (name == null) {
return "";
} else {
return name;
}
}
How can this be done?
JAXB doesn't generate the same code for an element with default value as it does for an attribute with default value because the XML schema differentiates between element and attribute defaults:
Default values of both attributes and elements are declared using the default attribute, although this attribute has a slightly different consequence in each case. When an attribute is declared with a default value, the value of the attribute is whatever value appears as the attribute's value in an instance document; if the attribute does not appear in the instance document, the schema processor provides the attribute with a value equal to that of the default attribute. Note that default values for attributes only make sense if the attributes themselves are optional, and so it is an error to specify both a default value and anything other than a value of optional for use.
The schema processor treats defaulted elements slightly differently. When an element is declared with a default value, the value of the element is whatever value appears as the element's content in the instance document; if the element appears without any content, the schema processor provides the element with a value equal to that of the default attribute. However, if the element does not appear in the instance document, the schema processor does not provide the element at all. In summary, the differences between element and attribute defaults can be stated as: Default attribute values apply when attributes are missing, and default element values apply when elements are empty.
You can always count on the default value for a missing attribute (from here the special getter) but there is a catch with a missing element value.
Nonetheless, when you unmarshall an instance, the unmarshaller knows how to handle the default value. See here for details:
Element default values and marshalling
Element default values and unmarshalling
XJC won't add the getter code or initialize the fields with the default value, so if you need the "null safe check" you can either add it yourself manually after the code is generated by XJC or try to use some plugin to do it automatically:
JAXB 2 Default Value Plugin
CXF XJC Default Value Plugin

How can I make #XmlAttribute in a special order by using JAXB?

I have XML file which needs 3 attributes in an element. How can make the order of street, zip and city attribute as I wanted?
<address street="Big Street" zip="2012" city="Austin">
</address>
#XmlType(name="Street)
#XmlRootElement(name = "Street")
public class Street {
#XmlAttribute
private String name;
#XmlAttribute
private String type;
... set and get method
}
Anecdotally, the attributes seem to be in reverse order than they are mentioned in code. In my case, I'm using two variables (name & value) and I had to declare them as:
// The inverse order of name & value seems to make them render in XML in name/value order
#XmlAttribute
protected String value;
#XmlAttribute
protected String name;
When the XML is generated, it results in the following:
<attribute name="nameValue" value="valueValue"/>
You can use #XmlAccessorOrder(has predefined values) or #XmlType(Only works for properties) to govern the ordering.
Samples
Edit :
For custom ordering JAXB specification doesnt provide anything, but you can do if your JAXB provider provides you some features.
Found this link where it speaks about ordering using EclipseLink JAXB.

Unqualified Element with Qualified Type Reference

I am essentially trying to produce the following chunk of XML from JAXB Annotations.
<pCredentials xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:type="ns3:LoginCredentials">
<loginId>user</loginId>
<loginPassword>password</loginPassword>
<userType>super</userType>
</pCredentials>
I tried the following annotations and multiple variations of the same type:
#XmlElement(name = "pCredentials", namespace = "##default", type = com.foo.LoginCredentials.class)
private LoginCredentials pCredentials;
But it produces the following:
<pCredentials>
<loginId>user</loginId>
<loginPassword>password</loginPassword>
<userType>super</userType>
</pCredentials>
Any suggestions as to what type of annotations I can provide that will produce the type reference?
Thanks for the help...Jay
You JAXB implementation will only add an xsi:type attribute when the Java type of the value does not match the expected type of the element. This is why what you tried will not work (since you are saying the elements type is the same type as the value.
You could do the following:
#XmlElement(type = Object.class)
private LoginCredentials pCredentials;
Note
The xsi:type attribute will be required in the XML being unmarshalled.
You will need to include LoginCredentials in the list of classes given to bootstrap the JAXBContext.
For More Information
http://blog.bdoughan.com/2010/11/jaxb-and-inheritance-using-xsitype.html

Resources