jaxb unmarshalling with namespace - java

This is my xml, need to convert it into java. I had used jaxb
<?xml version="1.0"?>
<lm:order Id="PLG24M240U" JD="" aCount="2" SUCount="1" xmlns:lm="http://www.ae.com/Event/Load">
<lm:master>
<lm:ID>3</lm:ID>
<lm:Number>313</lm:Number>
<lm:ANumber>323</lm:ANumber>
</lm:master>
<lm:detail>
<lm:ID>3</lm:ID>
<lm:Number>3131</lm:Number>
<lm:ANumber>3232</lm:ANumber>
</lm:detail>
<lm:detail>
<lm:ID>3</lm:ID>
<lm:Number>3131</lm:Number>
<lm:ANumber>3232</lm:ANumber>
</lm:detail>
<lm:detail>
<lm:ID>3</lm:ID>
<lm:Number>313</lm:Number>
<lm:ANumber>323</lm:ANumber>
</lm:detail>
</lm:order>
And throwing the following exception
javax.xml.bind.UnmarshalException: unexpected element (uri:"http://www.ae.com/Event/Load", local:"Order"). Expected elements are <{}lm:Order>
This is my unmarshalling code
jaxbContext = JAXBContext.newInstance(Order.class);
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
Order order = (Order) jaxbUnmarshaller.unmarshal(file);
System.out.println(order );
Order Pojo class
import java.util.ArrayList;
import java.util.List;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
#XmlAccessorType(XmlAccessType.FIELD)
#XmlRootElement(name = "lm:Order")
public class OrderPay {
#XmlAttribute
private String Id;
#XmlAttribute
private String JD;
#XmlAttribute
private String aCount;
#XmlAttribute
private String pCount;
/*#XmlElement
private Master master;
#XmlElement
private List<Detail> details = new ArrayList<Detail>();*/
}
Can you please help me in reading also, currently reading through file, need to read as an XML String.

The namespace attribute xmlns:lm="http://www.ae.com/Event/Load" might be the culprit here. In order to specify the namespace prefix, you can add the #XmlSchema annotation to a package-info.java file like this:
#XmlSchema(
namespace="http://www.ae.com/Event/Load",
elementFormDefault=XmlNsForm.QUALIFIED),
xmlns={#XmlNs(prefix="lm", namespaceURI="http://www.ae.com/Event/Load")})
package your.package;
import javax.xml.bind.annotation.*;

Related

ignore root element in JAXB

I'm trying to parse an xml file using JAXB.
My problem is that I need to skip the root node, If I delete it from the xml file I get what I need, otherwise - I get an empty object.
I'll give a simplified xml and my code (It behaves the same way):
XML:
<?xml version="1.0" encoding="utf-8"?>
<Root>
<!-- <Root xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="Office.xsd">
-->
<Office>
<Employees>
<Employee>
<name>George</name>
<rank>3</rank>
</Employee>
<Employee>
<name>Michael</name>
<rank>5</rank>
</Employee>
<Employee>
<name>Jeff</name>
<rank>1</rank>
</Employee>
<Employee>
<name>Todd</name>
<rank>7</rank>
</Employee>
<Employee>
<name>Jessica</name>
<rank>5</rank>
</Employee>
</Employees>
</Office>
</Root>
Office class:
import javax.xml.bind.annotation.*;
import java.util.Vector;
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class Office {
#XmlElementWrapper(name = "Employees")
#XmlElement(name = "Employee")
private Vector<Employee> employees;
}
Employee class:
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAccessType;
#XmlAccessorType(XmlAccessType.FIELD)
public class Employee {
#XmlElement(name="name")
private String name;
#XmlElement(name="rank")
private int rank;
public void promote() {
rank++;
}
}
Driver:
import javax.xml.stream.*;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.Marshaller;
import java.io.FileReader;
public class Driver {
public static void main (String[] args) {
parseOffice();
}
public static void parseOffice() {
try {
XMLInputFactory f = XMLInputFactory.newInstance();
XMLStreamReader reader = f.createXMLStreamReader(new FileReader("Office.xml"));
JAXBContext context = JAXBContext.newInstance(Office.class);
Unmarshaller unmarshaller = context.createUnmarshaller();
Office office = unmarshaller.unmarshal(reader, Office.class).getValue();
Marshaller marshaller = context.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(office, System.out);
}
catch (Exception e) {
e.printStackTrace();
}
}
}
You can parse the XML with a StAX XMLStreamReader, then advance it to the element you want to unmarshal, and then unmarshal it.
I posted a full example that should help on the related question linked below:
How to unmarshall SOAP response using JAXB if namespace declaration is on SOAP envelope?
Why don't you create a generic root element?
#XmlRootElement(name="Root" ...)
public class Root {
#XmlAnyElement(lax=true)
private Object content;
}
Add it to your context and unmarshal. You should get a JAXBElement<Office> as content.
Simply add the root class in hierarcy. And get Office class from Root class.
Root Class:-
import javax.xml.bind.annotation.*;
import java.util.Vector;
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class Root {
#XmlElement(name = "Office")
private Office office;
}
Office class
import javax.xml.bind.annotation.*;
import java.util.Vector;
#XmlAccessorType(XmlAccessType.FIELD)
public class Office {
#XmlElementWrapper(name = "Employees")
#XmlElement(name = "Employee")
private Vector<Employee> employees;
}
Change in parse method :-
JAXBContext context = JAXBContext.newInstance(Root.class);
Unmarshaller unmarshaller = context.createUnmarshaller();
Root root = unmarshaller.unmarshal(reader, Root.class).getValue();
Office office = root.getOffice();

#XmlSchema: "annotation type not applicable to this kind of declaration"

2.11 and java7. I'm trying to annotate my package with #XmlSchema as seen below.
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlNsForm;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlSchema;
#XmlSchema(namespace = "http://www.sitemaps.org/schemas/sitemap/0.9",
elementFormDefault = XmlNsForm.QUALIFIED)
#XmlRootElement(name="urlset")
public class Urlset {
private String name;
#XmlElement
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
However I'm getting this compiling error, "annotation type not applicable to this kind of declaration"
Does anybody know why this might be happening happening?
The #XmlSchema annotation is a package annotation, so put it in a file called package-info.java, located in the same source directory as Urlset.java, like so:
#XmlSchema(namespace = "http://www.sitemaps.org/schemas/sitemap/0.9",
elementFormDefault = XmlNsForm.QUALIFIED)
Remove that same annotation from your Urlset class.

Reading xmlAttribute from XmlElement in jaxB

Hello i have the following xml:
With the following code:
How can I get the attribute DispalyName of each element without creating new class for Down and Up and using #xmlAttribute.
I can solve it by adding new 2 classes UpElement and DownElement and for each class get the the #xmlAttribute but i want to it in once class.
Code Example:
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement(name = "StatusesList")
#XmlAccessorType(javax.xml.bind.annotation.XmlAccessType.FIELD)
public class StatusesListElement
{
#XmlElement(name = "Down")
private String down = "";
#XmlElement(name = "Up")
private String up = "";
public String getDown()
{
return down;
}
public void setDown(String down)
{
this.down = down;
}
public String getUp()
{
return up;
}
public void setUp(String up)
{
this.up = up;
}
}
Note: I'm the EclipseLink JAXB (MOXy) lead and a member of the JAXB 2 (JSR-222) expert group.
Using EclipseLink JAXB (MOXy)
You could use the #XmlPath extension in MOXy to map this use case:
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement(name = "StatusesList")
#XmlAccessorType(javax.xml.bind.annotation.XmlAccessType.FIELD)
public class StatusesListElement
{
#XmlPath("Down/#DisplayName")
private String down = "";
#XmlElement(name = "Up/#DisplayName")
private String up = "";
}
Using any JAXB Implementation
You could use an XmlAdapter for this use case. Below is a link to an answer I gave that demonstrates how this can be done:
JAXB Element mapping

Jaxb complex xml unmarshall

I am having issues to unmarshall nested xml below. Can someone please advise if I am missing something.
body tag can contain any Jaxb anotated obj.
Do I have to create a custom adapter for marshalling/unmarshalling such xml?
Input XML
<?xml version="1.0" encoding="UTF-8"?>
<serviceRq xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:type="serviceRq">
<body>
<createRq>
<id>1234</id>
</createRq>
</body>
</serviceRq>
My Jaxb-annotated classes are:
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "serviceRq")
public class ServiceRq{
private Object body;
<!-- getters and setters omitted-->
}
Here, body can be any jaxb annotated object, in this case its CreateRq.
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "createRq")
public class CreateRq{
private String id;
<!-- getters and setters omitted-->
}
I am looking for a generic way to support any Jaxb annotated object in body of the input xml.
You could use a #XmlAnyElement(lax=true) and an XmlAdapter to handle this use case:
ServiceRq
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "serviceRq")
public class ServiceRq{
#XmlJavaTypeAdapter(value=BodyAdapter.class)
private Object body;
// getters and setters omitted
}
BodyAdapter
import javax.xml.bind.annotation.adapters.XmlAdapter;
public class BodyAdapter extends XmlAdapter<Body, Object>{
#Override
public Object unmarshal(Body v) throws Exception {
return v.getValue();
}
#Override
public Body marshal(Object v) throws Exception {
Body body = new Body();
body.setValue(v);
return body;
}
}
Body
import javax.xml.bind.annotation.XmlAnyElement;
public class Body {
private Object value;
#XmlAnyElement(lax=true)
public Object getValue() {
return value;
}
public void setValue(Object value) {
this.value = value;
}
}
CreateRq
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "createRq")
public class CreateRq{
private String id;
// getters and setters omitted
}
Demo
import java.io.File;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(ServiceRq.class);
System.out.println(jc);
Unmarshaller unmarshaller = jc.createUnmarshaller();
ServiceRq serviceRq = (ServiceRq) unmarshaller.unmarshal(new File("input.xml"));
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(serviceRq, System.out);
}
}
For More Information
http://bdoughan.blogspot.com/2010/08/using-xmlanyelement-to-build-generic.html
http://bdoughan.blogspot.com/2010/07/xmladapter-jaxbs-secret-weapon.html
http://bdoughan.blogspot.com/2010/12/jaxb-and-immutable-objects.html
http://bdoughan.blogspot.com/2010/12/represent-string-values-as-element.html
You could use #XmlAnyElement(lax=true) and the #XmlPath extension in EclipseLink JAXB (MOXy) to handle this use case (Note: I'm the MOXy lead). For an approach that would work with any JAXB implementation (Metro, MOXy, JaxMe, etc) see: Jaxb complex xml unmarshall.
ServiceRq
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAnyElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
import org.eclipse.persistence.oxm.annotations.XmlPath;
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "serviceRq")
public class ServiceRq{
#XmlPath("body/createRq")
#XmlAnyElement(lax=true)
private Object body;
// getters and setters omitted
}
CreateRq
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "createRq")
public class CreateRq{
private String id;
// getters and setters omitted
}
Demo
import java.io.File;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(ServiceRq.class);
Unmarshaller unmarshaller = jc.createUnmarshaller();
ServiceRq serviceRq = (ServiceRq) unmarshaller.unmarshal(new File("input.xml"));
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(serviceRq, System.out);
}
}
jaxb.properties
To use MOXy as your JAXB provider you must include a file named jaxb.properties in the same package as your domain model with the following entry:
javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory
For More Information
http://bdoughan.blogspot.com/2010/08/using-xmlanyelement-to-build-generic.html
http://bdoughan.blogspot.com/2011/05/specifying-eclipselink-moxy-as-your.html
http://bdoughan.blogspot.com/2010/09/xpath-based-mapping-geocode-example.html
http://bdoughan.blogspot.com/2011/03/map-to-element-based-on-attribute-value.html

Configuring collection of polymorphic objects to work in JAXB2

I'm switching from Castor to JAXB2 to perform marshaling/unmarshaling between XML and Java object. I'm having problem trying to configure a collection of polymorphic objects.
Sample XML
<project name="test project">
<orange name="fruit orange" orangeKey="100" />
<apple name="fruit apple" appleKey="200" />
<orange name="fruit orange again" orangeKey="500" />
</project>
Project class
The oranges list works fine, I'm seeing 2 oranges in the list. But, I'm not sure how to configure fruitList. The fruitList should have 3 fruit: 2 oranges and 1 apple.
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class Project {
#XmlAttribute
private String name;
#XmlElement(name = "orange")
private List<Orange> oranges = new ArrayList<Orange>();
// Not sure how to configure this... help!
private List<Fruit> fruitList = new ArrayList<Fruit>();
}
Fruit class
Fruit is an abstract class. For some reason, defining this class as an abstract seems to be causing a lot of problems.
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public abstract class Fruit {
#XmlAttribute
private String name;
}
Orange class
public class Orange extends Fruit {
#XmlAttribute
private String orangeKey;
}
Apple class
public class Apple extends Fruit {
#XmlAttribute
private String appleKey;
}
How do I configure my fruitList in Project to achieve what I want here?
Thanks much!
You want to leverage #XmlElementRef this is corresponds to the XML schema concept of substitution groups which corresponds to your question.
Step 1 - Using #XmlElementRef
The fruitList property is annotated with #XmlElementRef:
import java.util.ArrayList;
import java.util.List;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElementRef;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class Project {
#XmlAttribute
private String name;
#XmlElementRef
private List<Fruit> fruitList = new ArrayList<Fruit>();
}
Step 2 - Annotate Apple and Orange with #XmlRootElement
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class Apple extends Fruit {
#XmlAttribute
private String appleKey;
}
and
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class Orange extends Fruit {
#XmlAttribute
private String orangeKey;
}
Demo Code
The following code can be used to demonstrate the solution:
import java.io.File;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(Project.class, Apple.class, Orange.class);
Unmarshaller unmarshaller = jc.createUnmarshaller();
Project project = (Project) unmarshaller.unmarshal(new File("input.xml"));
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(project, System.out);
}
}
For More Information:
http://bdoughan.blogspot.com/2010/11/jaxb-and-inheritance-using-substitution.html
After futzing around... I think I got it working now:-
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class Project {
#XmlAttribute
private String name;
// this has to be commented out, or else oranges won't show up in fruitList
// #XmlElement(name = "orange")
// private List<Orange> oranges = new ArrayList<Orange>();
#XmlElements({
#XmlElement(name = "orange", type = Orange.class),
#XmlElement(name = "apple", type = Apple.class)
})
private List<Fruit> fruitList = new ArrayList<Fruit>();
}
Put XmlAnyElement annotation:
#XmlAnyElement(lax = true)
private List<Fruit> fruitList = new ArrayList<Fruit>();

Categories

Resources