JAXB XMLElementWrapper with attribute and value - jaxb

Im trying to create an xml file which is similar looking to the below menetioned.
<message>
<header>
<params>
<param name="test1">value1</param>
<param name="test2">value2</param>
</params>
</header>
</message>
Can you please let me know, how to define the class hierarchy.
Thanks,
Prakash.A

#XmlRootElement
public class Message {
#XmlElement
private Header header;
}
public class Header {
#XmlElement(name="param")
#XmlElementWrapper
private Collection<Param> params;
}
public class Param {
#XmlAttribute
private String name;
#XmlValue
privaet String value;
}
getters/setters on your mark.

The best way to use #XmlElementWrapper.
shouled be denoted the name. like #XmlElementWrapper(name="params") though in this situation the default name is the properties's name.

Related

JAXB and MOXy xml and json marshalling of generic list in jersey

I'm making a little restful client in Jersey, and i have come into a little trouble with supporting both XML and JSON marshaling.
The specific problem is about marshaling an object that holds a few properties, with a generic list included.
I have the following class annotated as followed:
#XmlRootElement
public class Block<E> {
private String headerText;
private List<E> elements;
public Block() {
}
#XmlElement
public String getHeaderText() {
return headerText;
}
#XmlElementWrapper(name = "elements")
#XmlElements({
#XmlElement(name = "element", type=Foo.class),
#XmlElement(name = "element", type=Bar.class)
})
public List<E> getElements() {
return elements;
}
}
The XML comes out fine:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<block>
<elements>
<element>
<id>1</id>
<title>Title01</title>
</element>
<element>
<id>2</id>>
<title>Title02</title>
</element>
</elements>
<headerText>FooBarHeader</headerText>
</block>
but the JSON is formatted like this
{
-elements : {
-element: [
- {
id : 1
title : "Title01"
}
- {
id : 2
title : "Title02"
}
]
}
headerText : "HeaderText"
}
I would of course be interested in not having the "element" property in my JSON output, and only have elements: [{}...{}]
I have already setup a ContextResolver that creates a MOXyConfig with properties for JSON_WRAPPER_AS_ARRAY_NAME - and this works fine for fx. A List<String> where I only have to declare the property with #XmlElement instead of #XmlElements.
Anyone who know of a solution of this problem?
JSON_WRAPPER_AS_ARRAY_NAME Property
The effect of the JSON_WRAPPER_AS_ARRAY_NAME property (see: http://blog.bdoughan.com/2013/03/binding-to-json-xml-handling-collections.html) depends on whether the item names are significant or not,
Insignificant Item Names
Below we know that each item in the collection is an instance of Foo or an instance of a subclass of Foo.
#XmlElementWrapper(name = "elements")
#XmlElement(name = "element")
public List<E> getElements() {
return elements;
}
Significant Item Names
In the case of #XmlElements the item name is significant since it tells us which class we need to instantiate on the unmarshal and can not be excluded.
#XmlElementWrapper(name = "elements")
#XmlElements({
#XmlElement(name = "foo", type=Foo.class),
#XmlElement(name = "bar", type=Bar.class)
})
public List<E> getElements() {
return elements;
}
What You Can Do
You can use MOXy's externmal mapping document to override the mapping for the elements property to the following:
#XmlElementWrapper(name = "elements")
#XmlElement(name = "foo")
public List<E> getElements() {
return elements;
}
Then the JAXBContext for XML will be based on the annotations, and the JAXBContext for JSON will be based on the annotatons and external mapping document.
For More Information
http://blog.bdoughan.com/2010/12/extending-jaxb-representing-annotations.html
http://blog.bdoughan.com/2011/09/mapping-objects-to-multiple-xml-schemas.html
Try registering another JSON Entity Provider, which will disable automatically Moxy for JSON marshalling (see the ref). If you enable e.g Jackson, you will have its own annotations to control how everything is marshalled.

XML element with two attributes and simple element using JAXB

I would like to un marshall using JAXB. I am facing issue while unmarshalling for the following use case.
Please suggest how to generate below xml using JAXB.
<Source type="system" gender="male">
<Description>He is a man</Description>
</Source>
You can do the following. The #XmlAttribute annotation is used to mark something an XML attribute. By default everything is treated as an element, if you need the name different from the default then you can use the #XmlElement annotation to specify this.
#XmlRootElement(name="Source")
#XmlAccessorType(XmlAccessType.FIELD)
public class Source {
#XmlAttribute
private String type;
#XmlAttribute
private String gender;
#XmlElement(name="Description")
private String description;
}

How to ignore JAXB annotated properties in a parent class?

We have a class with a JAXB annotation on one property. We then have several subclasses which annotate the rest of the important data. We have one subclass, however, where we want to ignore the parent class annotation so that it does not get marshalled. Here's some example code.
Parent class:
#XmlType(name="Request")
#XmlAccessorType(XmlAccessorType.NONE)
public abstract class Request {
#XmlElement(required=true)
private UUID uuid;
... setter/getter
}
Now for the subclass:
#Xsd(name="concreteRequest")
#XmlRootElement("ConcreteRequest")
#XmlType(name="ConcreteRequest")
#XmlAccessorType(XmlAccessorType.FIELD)
public class ConcreteClass {
#XmlElement(required=true)
private String data1;
#XmlElement(required=true)
private String data1;
... setters/getters ...
}
When I masrhall an instance of ConcreteClass I get the following XML:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ConcreteRequest>
<uuid>uuid</uuid>
<data1>data</data1>
<data2>data</data3>
</ConcreteRequest>
Where I want XML like this:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ConcreteRequest>
<data1>data</data1>
<data2>data</data3>
</ConcreteRequest>
We have other implementations of Request, however that do require the UUID, this is just a special case. Is there a way to ignore the UUID field in my ConcreteRequest?
I hope, I understood your problem. Here is the solution.
JAXB provides #XmlTransient(javax.xml.bind.annotation.XmlTransient)(javadoc) to ignore any field during marshalling.
Override the field "uuid" as #XmlTransient in your derived class (ConcreteRequest.class) along with its correspoding Getter/Setter method. It is necessary to override the Getter/Setter methods also, these will be invoked during marshalling.
#Xsd(name="concreteRequest")
#XmlRootElement("ConcreteRequest")
#XmlType(name="ConcreteRequest")
#XmlAccessorType(XmlAccessorType.FIELD)
public class ConcreteClass {
#XmlElement(required=true)
private String data1;
#XmlElement(required=true)
private String data2;
#XmlTransient
private UUID uuid;
... setters/getters ...
}
This will override your Base Class attribute.
Get back to me for more information.
You can use
#XmlAccessorType(XmlAccessType.NONE)
on parent class, and
#XmlAccessorType(XmlAccessType.FIELD)
on derived class.

jaxb annotations for verbose OTA XML

For my sins, I'm working with Airline OTA XML. It has verbose elements such as:
<FlightInfo>
<Success />
<DepartureAirport LocationCode="LHR" />
<ArrivalAirport LocationCode="LAX" />
</FlightInfo>
where the presence of a Success element means the response is successful, and airport codes are embedded as Attributes in holding Elements.
To preserve my sanity as I write java code, I want to convert this into a simple POJO like this:
public class FlightInfo {
private boolean success;
private String departureAirport;
private String arrivalAirport;
}
Using JAXB, what is the recommended approach for this - use XmlJavaTypeAdapter for all these elements?
Note: I'm the EclipseLink JAXB (MOXy) lead and a member of the JAXB 2 (JSR-222) expert group.
You could use the #XmlPath extension in MOXy for the departureAirport and arrivalAirport fields:
#XmlPath("DepartureAirport/#LocationCode")
private String departureAirport;
#XmlPath("ArrivalAirport/#LocationCode")
private String arrivalAirport;
And you could use an XmlAdapter to represent the boolean field success with the presence or absence of the Success element:
#XmlJavaTypeAdapter(SuccessAdapter.class)
private boolean success;
FlightInfo
Below is what your FlightInfo class would look like with MOXy and JAXB annotations:
import javax.xml.bind.annotation.*;
import org.eclipse.persistence.oxm.annotations.*;
#XmlRootElement(name="FlightInfo")
#XmlAccessorType(XmlAccessType.FIELD)
public class FlightInfo {
#XmlJavaTypeAdapter(SuccessAdapter.class)
private boolean success;
#XmlPath("DepartureAirport/#LocationCode")
private String departureAirport;
#XmlPath("ArrivalAirport/#LocationCode")
private String arrivalAirport;
}
For More Information
http://blog.bdoughan.com/2010/09/xpath-based-mapping-geocode-example.html
http://blog.bdoughan.com/2010/12/represent-string-values-as-element.html
http://blog.bdoughan.com/2011/05/specifying-eclipselink-moxy-as-your.html

Add/Override behavior on Jaxb generated classes by extending them

I have a web server responding with xml data and a client consuming it.
Both share the same domain code. One of the domain objects looks like this:
#XmlAccessorType(XmlAccessType.PUBLIC_MEMBER)
#XmlRootElement(name = "image")
public class Image {
private String filename;
private ImageTypeEnum type;
#XmlElement(name = "imageUri")
public String getAbsoluteUri() {
// some complex computation
return uri;
}
}
When I try to unmarshal the response from the server into this object, since there's no setter for absoluteUri, I don't have the imageUri in the class. So I extend it like this:
public class FEImage extends Image{
private String imageUri;
public String getAbsoluteUri() {
return imageUri;
}
public void setAbsoluteUri(String imageUri) {
this.imageUri = imageUri;
}
}
My ObjectFactory
#XmlRegistry
public class ObjectFactory {
public Image createImage(){
return new FEImage();
}
}
My code to unmarshal is here:
JAXBContext context = JAXBContext.newInstance(ObjectFactory.class);
Unmarshaller unmarshaller = context.createUnmarshaller();
unmarshaller.setProperty("com.sun.xml.bind.ObjectFactory",new ObjectFactory());
((JAXBElement)unmarshaller.unmarshal((InputStream) response.getEntity())).getValue();
However, the setAbsoluteUri doesn't seem to be getting called in FEImage while unmarshalling. When I add a dummy setAbsoluteUri in Image.java, everything works as expected.
Can someone tell me how can I cleanly extend from Image.java?
Note: I'm the EclipseLink JAXB (MOXy) lead and a member of the JAXB 2 (JSR-222) expert group.
A JAXB implementation is not required to use the ObjectFactory class when instantiating an object. You can configure instantiation to be done via a factory class using the #XmlType annotation:
#XmlType(factoryClass=ObjectFactory.class, factoryMethod="createImage")
public class Image {
private String filename;
private ImageTypeEnum type;
#XmlElement(name = "imageUri")
public String getAbsoluteUri() {
// some complex computation
return uri;
}
}
http://blog.bdoughan.com/2011/06/jaxb-and-factory-methods.html
If you do the above, then your JAXB implementation will still use the Image class to derive the metadata so it will not solve your problem. An alternate approach would be to use an XmlAdapter for this use case:
http://blog.bdoughan.com/2010/12/jaxb-and-immutable-objects.html
Better still, when a property on your domain object does not have a setter, you can tell your
JAXB implementation (EclipseLink MOXy, Metro, Apache JaxMe, etc) to use field (instance variable) access instead using #XmlAccessorType(XmlAccessType.FIELD):
#XmlAccessorType(XmlAccessType.FIELD)
public class Image {
}
http://blog.bdoughan.com/2011/06/using-jaxbs-xmlaccessortype-to.html
UPDATE #1
If you are not able to modify the domain objects, then you may be interested in MOXy's externalized metadata. This extension provides a means via XML to provide JAXB metadata for classes where you cannot modify the source.
For More Information
http://blog.bdoughan.com/2010/12/extending-jaxb-representing-annotations.html
http://wiki.eclipse.org/EclipseLink/UserGuide/MOXy/Runtime/XML_Bindings
UPDATE #2 - Based on results of chat
Image
Below is the implementation of the Image class that I will use for this example. For the complex computation of getAbsoluteUri() I simply add the prefix "CDN" to the filename:
package forum7552310;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
#XmlAccessorType(XmlAccessType.PUBLIC_MEMBER)
#XmlRootElement(name = "image")
public class Image {
private String filename;
private ImageTypeEnum type;
#XmlElement(name = "imageUri")
public String getAbsoluteUri() {
return "CDN" + filename;
}
}
binding.xml
Below is the MOXy binding document I put together. In this file I do a few things:
Set XmlAccessorType to FIELD
Mark the absoluteURI property to be XmlTransient since we will be mapping the filename field instead.
Specify that an XmlAdapter will be used with the filename field. This is to apply the logic that is done in the getAbsoluteUri() method.
<?xml version="1.0"?>
<xml-bindings
xmlns="http://www.eclipse.org/eclipselink/xsds/persistence/oxm"
package-name="forum7552310">
<java-types>
<java-type name="Image" xml-accessor-type="FIELD">
<java-attributes>
<xml-element java-attribute="filename" name="imageUri">
<xml-java-type-adapter value="forum7552310.FileNameAdapter"/>
</xml-element>
<xml-transient java-attribute="absoluteUri"/>
</java-attributes>
</java-type>
</java-types>
</xml-bindings>
FileNameAdapter
Below is the implementation of the XmlAdapter that applies the same name algorithm as the getAbsoluteUri() method:
package forum7552310;
import javax.xml.bind.annotation.adapters.XmlAdapter;
public class FileNameAdapter extends XmlAdapter<String, String> {
#Override
public String marshal(String string) throws Exception {
return "CDN" + string;
}
#Override
public String unmarshal(String adaptedString) throws Exception {
return adaptedString.substring(3);
}
}
Demo
Below is the demo code demonstrating how to apply the binding file when creating the JAXBContext:
package forum7552310;
import java.io.File;
import java.util.HashMap;
import java.util.Map;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import org.eclipse.persistence.jaxb.JAXBContextFactory;
public class Demo {
public static void main(String[] args) throws Exception {
Map<String, Object> properties = new HashMap<String, Object>(1);
properties.put(JAXBContextFactory.ECLIPSELINK_OXM_XML_KEY, "forum7552310/binding.xml");
JAXBContext jc = JAXBContext.newInstance(new Class[] {Image.class}, properties);
File xml = new File("src/forum7552310/input.xml");
Unmarshaller unmarshaller = jc.createUnmarshaller();
Image image = (Image) unmarshaller.unmarshal(xml);
System.out.println(image.getAbsoluteUri());
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(image, System.out);
}
}
jaxb.properties
You need to include a file named jaxb.properties with the following contents in the same package as your Image class:
javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory
input.xml
Here is the XML input I used:
<?xml version="1.0" encoding="UTF-8"?>
<image>
<imageUri>CDNURI</imageUri>
</image>
Output
And here is the output from running the demo code:
CDNURI
<?xml version="1.0" encoding="UTF-8"?>
<image>
<imageUri>CDNURI</imageUri>
</image>

Resources