JAXB XML to Object - jaxb

I am trying to unmarshal the data of XML. If XML structure is like the structure given below then How to made the class to print both the values of attribute as well as element. I want to unmarshal it and consider that Vehicle is one class and Accessory is another class and accessory is made as attribute to Vehicle class. I want the class structure so that the object, I get after unmarshalling will be used to get both the values "Wind Screen" and "My wind screen is broken".
<Vehicle>
<Accessory type="Wind Screen">My wind screen is broken</Accessory>
</Vehicle>

As per your XML, Accessory cannot be attribute but element to the Vehicle.
With below class, you can unmarshall the Vehicle object and retrieve the values from Accessory class. Or you can overrride toString() method of Vehicle class to print the values of Accessory attribute type and content.
Vehicle.class
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "Vehicle", propOrder = {
})
public class Vehicle
{
#XmlElement(name = "Accessory")
protected Accessory accessory;
// other elements
}
Accessory.class
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "Accessory", propOrder = {
"value"
})
public class Accessory
{
#XmlValue
protected String value;
#XmlAttribute(name = "type")
#XmlSchemaType(name = "anySimpleType")
protected String type;
// getters and setters ommitted for brevity.
}

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.

Handling of XML elements with different name but similar structure using JAXB

I have a XML file with elements having different names but similar structure(same attributes and child elements). I want to convert XML file to Java objects. I have used #XmlAnyElement annotation and it gives the element but it is not convertible to the Java object class. Through eclipse debugging I have verified that it is in the form ElementNSImpl which cannot be cast to the Object class.
Sample XML structure is following,
<element1 attr1="" attr2="" attr3="">
<childElement1>
<childElement2>
</element1>
<element2 attr1="" attr2="" attr3="">
<childElement1>
<childElement2>
</element2>
I am using JAXB annotations.
Root
In JAXB Java classes correspond to complex types in XML Schema. If element1 and element2 have the same type then they refer to the same class.
import javax.xml.bind.annotation.*;
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class Root {
private Element element1;
private Element element2;
}
Element
import javax.xml.bind.annotation.*;
#XmlAccessorType(XmlAccessType.FIELD)
public class Element {
#XmlAttribute
private String attr1;
#XmlAttribute
private String attr2;
#XmlAttribute
private String attr3;
private String childElement1;
private String childElement2;
}

IllegalAnnotationExceptions while converting object to XML using Jaxb

I have a TrainingCalendarWrapper class which have a list which hold TrainingCalendarVO. In my application
I'm setting the details in TrainingCalendarVO and then added to trainingList of TrainingCalendarWrapper
And then converting TrainingCalendarWrapper to XML using Jaxb.
#XmlRootElement
public class TrainingCalendarWrapper implements Serializable
{
public ArrayList<TrainingCalendarVO> trainingList;
Getters & Setters for trainingList
}
1 counts of illegalAnnotationException Class has two properties of the same name "trainingList" for the below line of code
JAXBContext jaxbContext = JAXBContext.newInstance(TrainingCalendarWrapper.class);
If you are annotating the fields (instance variables) then you need to specify #XmlAccessorType(XmlAccessType.FIELD) at the class level. Otherwise you can add the annotation to the get or set methods.
http://blog.bdoughan.com/2011/06/using-jaxbs-xmlaccessortype-to.html

Accessing attributes passed to extended PrimeFaces component

I'm trying to create a custom component to extend PrimeFaces.
I have a simple component called textInput under the test namespace that simply calls the PrimeFaces textInput component and prints out the value passed to an attribute named fieldClass and the names of any attributes passed
if I pass fieldClass as a string:
<test:textInput id="foo" fieldClass="field-foo" />
this is the result
fieldClass = field-foo
[com.sun.faces.facelets.MARK_ID, fieldClass]
If I pass fieldClass as an expression
<ui:param name="bar" value="field-foo"/>
<test:textInput id="foo" fieldClass="#{bar}" />
fieldClass vanishes
fieldClass = NONE
[com.sun.faces.facelets.MARK_ID]
How do I actually get hold of the attributes passed to the component?
Classes used by the custom component follows:
test.components.ExtendInputTextRenderer
package test.components;
import java.util.Map;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;
import javax.faces.context.ResponseWriter;
import javax.faces.render.FacesRenderer;
import org.primefaces.component.inputtext.*;
#FacesRenderer(
componentFamily=ExtendInputText.COMPONENT_FAMILY,
rendererType=ExtendInputTextRenderer.RENDERER_TYPE
)
public class ExtendInputTextRenderer extends InputTextRenderer {
public static final String RENDERER_TYPE = "com.example.ExtendInputTextRenderer";
#Override
public void encodeEnd(FacesContext context, UIComponent component)
throws java.io.IOException {
ResponseWriter writer = context.getResponseWriter();
Map attrs = component.getAttributes();
String fieldClass = attrs.containsKey("fieldClass") ? (String) attrs.get("fieldClass").toString() : "NONE";
writer.write("fieldClass = " + fieldClass + "<br/>");
writer.write(attrs.keySet().toString() + "<br/>");
super.encodeEnd(context, component);
}
}
test.components.ExtendInputText
package test.components;
import javax.faces.component.FacesComponent;
import org.primefaces.component.inputtext.InputText;
#FacesComponent(ExtendInputText.COMPONENT_TYPE)
public class ExtendInputText extends InputText {
public static final String COMPONENT_FAMILY = "com.example";
public static final String COMPONENT_TYPE = "com.example.ExtendInputText";
#Override
public String getFamily() {
return COMPONENT_FAMILY;
}
#Override
public String getRendererType() {
return ExtendInputTextRenderer.RENDERER_TYPE;
}
}
String fieldClass = attrs.containsKey("fieldClass") ? (String) attrs.get("fieldClass").toString() : "NONE";
Your mistake is that you're using containsKey() to check if the property has been specified.
Here's an extract from UIComponent#getAttributes() javadoc:
getAttributes
public abstract java.util.Map<java.lang.String,java.lang.Object> getAttributes()
Return a mutable Map representing the attributes (and properties, see below) associated wth this UIComponent, keyed by attribute name (which must be a String). The returned implementation must support all of the standard and optional Map methods, plus support the following additional requirements:
The Map implementation must implement the java.io.Serializable interface.
Any attempt to add a null key or value must throw a NullPointerException.
Any attempt to add a key that is not a String must throw a ClassCastException.
If the attribute name specified as a key matches a property of this UIComponent's implementation class, the following methods will have special behavior:
containsKey() - Return false.
get() - If the property is readable, call the getter method and return the returned value (wrapping primitive values in their corresponding wrapper classes); otherwise throw IllegalArgumentException.
put() - If the property is writeable, call the setter method to set the corresponding value (unwrapping primitive values in their corresponding wrapper classes). If the property is not writeable, or an attempt is made to set a property of primitive type to null, throw IllegalArgumentException.
remove() - Throw IllegalArgumentException.
Note that it thus always returns false for containsKey for component's properties. That's because dynamic properties are not stored in the attribute map, but instead in the component instance itself. They're only resolved when calling get().
You need to change the wrong line as follows:
String fieldClass = (String) attrs.get("fieldClass");
if (fieldClass == null) fieldClass = "NONE";

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