#XmlRootElement(name = "test")
public class MyDTO {
#XmlElement(name = "test2)
private MyObject meta;
}
Result:
{meta:{...}}
Problems:
I'd like to have some kind of "outer" tag named "test"
Why is the #XmlElement(name" attribute for meta not working?
my first post!
Indeed you can name your "outer" tag with #XmlRootElement. If you need another outer tag I am not sure how to realize this.
Your second concern might be because of the place where you put the #XmlElement. I placed it on my getter-method and it worked fine fore me.
For the JSON Output I used jersey-json-1.18.
The following works also for other complex types you could define instead of "String meta".
Here is the output I was able to produce:
As JSON
{"myId":"id1","myMeta":"text1"}
As XML
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<mytupel>
<myId>id1</myId>
<myMeta>text1</myMeta>
</mytupel>
This is my object:
#XmlRootElement(name = "mytupel")
public class Tupel {
// #XmlElement(name = ) does not work here - defined it on the getter method
private String id;
// #XmlElement(name = ) does not work here - defined it on the getter method
private String meta;
/**
* Needed for JAXB
*/
public Tupel() {
}
/**
* For Test purpose...
*/
public Tupel(String id, String text) {
super();
this.id = id;
this.meta = text;
}
#XmlElement(name = "myId")
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
#XmlElement(name = "myMeta")
public String getMeta() {
return meta;
}
public void setMeta(String meta) {
this.meta = meta;
}
/**
* For Test purpose...
*/
#Override
public String toString() {
return id + ": " + meta;
}
}
And here is my small class to produce the output XML files...
public class Main {
private static final String TUPEL_1_XML = "./tupel1.xml";
private static final String TUPEL_2_XML = "./tupel2.xml";
public static void main(String[] args) throws JAXBException, FileNotFoundException {
// init JAXB context/Marhsaller stuff
JAXBContext context = JAXBContext.newInstance(Tupel.class);
Marshaller marshaller = context.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
Unmarshaller unmarshaller = context.createUnmarshaller();
// create some Datatypes
Tupel data1 = new Tupel("id1", "text1");
Tupel data2 = new Tupel("id2", "42");
// produce output
marshaller.marshal(data1, new File(TUPEL_1_XML));
marshaller.marshal(data2, new File(TUPEL_2_XML));
// read from produced output
Tupel data1FromXml = (Tupel) unmarshaller.unmarshal(new FileReader(TUPEL_1_XML));
Tupel data2FromXml = (Tupel) unmarshaller.unmarshal(new FileReader(TUPEL_2_XML));
System.out.println(data1FromXml.toString());
System.out.println(data2FromXml.toString());
System.out.println(marshalToJson(data1FromXml));
System.out.println(marshalToJson(data2FromXml));
}
public static String marshalToJson(Object o) throws JAXBException {
StringWriter writer = new StringWriter();
JAXBContext context = JSONJAXBContext.newInstance(o.getClass());
Marshaller m = context.createMarshaller();
JSONMarshaller marshaller = JSONJAXBContext.getJSONMarshaller(m, context);
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshallToJSON(o, writer);
return writer.toString();
}
}
Hope this answers your question!
Cheers
Max
Related
I want to unmarshal this xml document that I am receiving from a REST call:
<ns2:hello xmlns:ns4="http://myspace.org/hello/history/1.0" xmlns:ns3="http://www.hello.com/IAP/im1_1_0" xmlns:ns2="http://www.w3.org/2005/Atom">
<ns3:totalEntries>7</ns3:totalEntries>
<ns2:id>123</ns2:id>
<ns2:title type="text">Users</ns2:title>
<ns2:updated>2017-08-22T07:51:27.270Z</ns2:updated>
<ns2:link href="https://example.com:8080/1/rest/users" rel="self"/>
<ns2:link href="https://example.com:8080/1/rest/users" rel="http://www.example.com/iap/im/user/create"/>
<ns4:complete/>
<ns2:entry>
<ns2:id>urn:uuid:f0fd4040-04da-11e7-8f6a-8e3ecfcb7035</ns2:id>
<ns2:title type="text">Hello</ns2:title>
<ns2:content type="application/vnd.bosch-com.im+xml">
<ns3:user>
<ns3:id>f0fd4040-04da-11e7-8f6a-8e3ecfcb7035</ns3:id>
<ns3:name>name</ns3:name>
<ns3:firstName>Hello</ns3:firstName>
<ns3:lastName>All</ns3:lastName>
</ns3:user>
</ns2:content>
</ns2:entry>
</ns2:hello>
As you can see the XML is nested, and for this I am using JAXB for unmarshalling:
try {
JAXBContext jc = JAXBContext.newInstance(Feed.class);
Unmarshaller um = jc.createUnmarshaller();
Feed feed = (Feed) um.unmarshal(new StringReader(userEntity.getBody()));
System.out.println(feed.getEntry().get(0).getContent().getUser().getFirstName());
}
catch (JAXBException e) {
e.printStackTrace();
}
But, I am not getting any data set into my POJO (it's null):
#XmlRootElement(namespace="http://www.w3.org/2005/Atom", name="hello")
public class Hello {
private String id;
private String totalEntries;
private String title;
private String updated;
List<Entry> entry;
Complete complete;
}
My POJO looks like above. Also I have created Entry and Complete POJO classes. How can I fix this?
The XML has 3 namespaces:
xmlns:ns4="http://myspace.org/hello/history/1.0"
xmlns:ns3="http://www.hello.com/IAP/im1_1_0"
xmlns:ns2="http://www.w3.org/2005/Atom"
You will need to ensure that each element is in the correct namespace #XmlElement(namespace="xmlns:ns3="http://www.hello.com/IAP/im1_1_0") etc, to be able to unmarshall correctly
You may Also benefit from adding #XmlType(propOrder = { "totalEntries", ...
Have you tried just adding getters and setters to the class Hello ?
Your sample works with this simplified version of Hello.
#XmlRootElement(namespace = "http://www.w3.org/2005/Atom", name = "hello")
public class Hello {
private String id;
private String title;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
}
And the Test class
public class Test {
public static void main(String[] args) {
try {
JAXBContext jc = JAXBContext.newInstance(Feed.class);
Unmarshaller um = jc.createUnmarshaller();
InputStream file = new FileInputStream("path/to/file/feed.xml");
Hello feed = (Hello) um.unmarshal(file);
System.out.println(feed.getId());
System.out.println(feed.getTitle());
} catch (JAXBException | FileNotFoundException e) {
e.printStackTrace();
}
}
}
Prints
123
Users
How can I to process such structure with the help of JAXB?
There is one parent root catalog and many other in it, that are keeping info about many objects (states, for example).
<?xml version='1.0' encoding='utf-8'?>
<root>
<states>
<state>
<name>Alabama</name>
<id>al</id>
</state>
<state>
<name>Alaska</name>
<id>ak</id>
</state>
...
</states>
<airports>
<airport>
...
</airport>
<airport>
...
</airport>
...
</airports>
...
</root>
In case states, I created class States:
#XmlRootElement(name = "root")
#XmlAccessorType(XmlAccessType.FIELD)
public class States {
#XmlElement(name="states")
private List<State> states;
public List<State> getBrokers(){
return states;
}
public void setBrokers(List<State> states) {
this.states = states;
}
}
and class State:
#XmlAccessorType(XmlAccessType.FIELD)
public class State {
#XmlElement(name = "name")
private String name;
#XmlElement(name = "id")
private String id;
public State(){}
public State(String id, String name) {
this.id = id;
this.name = name;
}
But when I call the States object
public class JaxbParser {
public Object getObject(File file, Class c) throws JAXBException {
JAXBContext context = JAXBContext.newInstance(c);
Unmarshaller unmarshaller = context.createUnmarshaller();
Object object = unmarshaller.unmarshal(file);
return object;
}
public void saveObject(File file, Object o) throws JAXBException {
JAXBContext context = JAXBContext.newInstance(o.getClass());
Marshaller marshaller = context.createMarshaller();
marshaller.marshal(o,file);
}
}
public static void main(String[] args) throws JAXBException {
JaxbParser parser = new JaxbParser();
States brol = (States) parser.getObject(new File("C:\\Users\\...\\1.xml"), States.class);
List<State> brokerList = brol.getStates();
System.out.println(brol);
}
the stateList contains only one state with id and name equals null.
What am I doing wrong ?
public static void main(String args[]) throws
JAXBException {
try {
File file = new File("....xml");
JAXBContext jaxbContext =
JAXBContext.newInstance(Classname.class);
Unmarshaller jaxbUnmarshaller =
jaxbContext.createUnmarshaller();
Classname objectName = (Classname)
jaxbUnmarshaller.unmarshal(file);
List<Classname> list = objectName.getStates();
int i = 1;
for (State ans : list){
.....
}
} catch (JAXBException e) {
e.printStackTrace();
}
}
I'm using JAXB to unmarshal a given input Xml file into Java object
and then marashal it back to Xml String.
My Xml file looks like this:
<bpmn2:definitions xmlns:bpmn2="http://www.omg.org/spec/BPMN/20100524/MODEL" id="_Definitions_1">
<bpmn2:process id="_500441" name="process">
</bpmn2:process>
</bpmn2:definitions>
Definitions.class:
#XmlRootElement(namespace = "http://www.omg.org/spec/BPMN/20100524/MODEL")
public class Definitions {
#XmlAttribute
private String id;
#XmlElement(name = "bpmn2:process")
private Process process;
#XmlElement(name = "bpmndi:BPMNDiagram")
private Diagram diagram;
public Definitions() {
}
public Definitions(String id, Process process, Diagram diagram) {
this.id = id;
this.process = process;
this.diagram = diagram;
}
public Process getProcess() {
return process;
}
public Diagram getDiagram() {
return diagram;
}
public String getId() {
return id;
}
}
Process.class:
#XmlAccessorType(XmlAccessType.FIELD)
public class Process {
#XmlAttribute
private String id;
public Process() {
}
public Process(String id) {
this.id = id;
}
public String getId() {
return id;
}
}
Model.class:
public class Model {
#XmlElement
private Process process;
public Model() {
}
public Model(String processId, Process p) {
this.id = processId;
this.process = p;
}
}
main method:
public static void main(String[] args) throws IOException, JSONException, JAXBException {
BpmnToJsonImport bj = new BpmnToJsonImport();
InputStream is = BpmnToJsonImport.class.getResourceAsStream("myXml.txt");
String Str = IOUtils.toString(is);
StringReader sr = new StringReader(Str);
JAXBContext context = JAXBContext.newInstance(Definitions.class, Model.class);
Unmarshaller unmarshaller = context.createUnmarshaller();
Definitions d = (Definitions) unmarshaller.unmarshal(sr);
Model model = new Model(d.getProcess().getId(), d.getProcess());
StringWriter sw = new StringWriter();
Marshaller marshaller = context.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");
marshaller.marshal(model, sw);
String str = sw.toString();
System.out.println(str);
}
Exactly when it tries to retrieve the process id using d.getProcess.getId I get the
java.lang.NullPointerException
You are mapping the namespace qualification incorrectly. You must not include the prefix in the element name.
#XmlElement(name = "BPMNDiagram")
private Diagram diagram;
To map the namespace qualification you can use the package level #XmlSchema annotation.
package-info.java
#XmlSchema(
namespace = "http://www.omg.org/spec/BPMN/20100524/MODEL",
elementFormDefault = XmlNsForm.QUALIFIED)
package example;
import javax.xml.bind.annotation.XmlNsForm;
import javax.xml.bind.annotation.XmlSchema;
For More Information
http://blog.bdoughan.com/2010/08/jaxb-namespaces.html
I need create/read xml file using default namespace:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<xmlBoo xmlns="http://www.example2.org/boo">
<customer>
<address>
<street>Wall Street</street>
</address>
<id>1</id>
<name>John</name>
</customer>
<someSpecificField>Specific data in Boo</ns2:someSpecificField>
</xmlBoo>
but I'm getting:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ns2:xmlBoo xmlns:ns2="http://www.example2.org/boo">
<ns2:customer>
<address>
<street>Wall Street</street>
</address>
<id>1</id>
<name>John</name>
</ns2:customer>
<ns2:someSpecificField>Specific data in Boo</ns2:someSpecificField>
</ns2:xmlBoo>
I know about package level metadata, but this is not working in complex package structure:
I have defined model classes like Address:
package example.model;
public class Address {
private String street;
Customer:
package example.model;
public class Customer {
private long id;
private String name;
private Address address;
The parent class for common fields:
package example.xml;
#XmlTransient
public class Xml {
private Customer customer;
Then specific classes which holds data/structure of concrete xml XmlBoo:
package example.xml.boo;
#XmlRootElement
public class XmlBoo extends Xml {
private String someSpecificField;
XmlFoo:
package example.xml.foo;
#XmlRootElement
public class XmlFoo extends Xml {}
package-info.java is included in two mentioned packages example.xml.boo:
#XmlSchema(
namespace = "http://www.example2.org/boo",
elementFormDefault = XmlNsForm.QUALIFIED)
package example.xml.boo;
and example.xml.foo:
#XmlSchema(
namespace = "http://www.example2.org/foo",
elementFormDefault = XmlNsForm.QUALIFIED)
package example.xml.foo;
And finally main method:
package example;
public class Demo {
public static void main(String... args) {
generateBoo();
generateFoo();
}
public static void generateBoo() {
try {
JAXBContext jc = JAXBContext.newInstance(XmlBoo.class);
Marshaller m = jc.createMarshaller();
m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
XmlBoo xmlBoo = new XmlBoo();
Customer customer = new Customer();
customer.setId(1);
customer.setName("John");
Address address = new Address();
address.setStreet("Wall Street");
customer.setAddress(address);
xmlBoo.setCustomer(customer);
xmlBoo.setSomeSpecificField("Specific data in Boo");
m.marshal(xmlBoo, System.out);
} catch (JAXBException e) {
e.printStackTrace();
}
}
public static void generateFoo() {
try {
JAXBContext jc = JAXBContext.newInstance(XmlFoo.class);
Marshaller m = jc.createMarshaller();
m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
XmlFoo xmlFoo = new XmlFoo();
Customer customer = new Customer();
customer.setId(1);
customer.setName("John");
Address address = new Address();
address.setStreet("Wall Street");
customer.setAddress(address);
xmlFoo.setCustomer(customer);
m.marshal(xmlFoo, System.out);
} catch (JAXBException e) {
e.printStackTrace();
}
}
}
I've tried both solutions like here and also without success.
It is possible remove & rename prefix if I have all classes in one package (and one package-info file)
It is possible rename but NOT remove prefix if I have complex package structure
Is there solution how I can remove ns2 prefix?
I'm using JDK7.
Solution how get (write & read xml) the needed result:
<?xml version="1.0" encoding="UTF-8"?>
<xmlBoo xmlns="http://www.example.org/boo" xmlns:c="http://www.example.org/customer" xmlns:a="http://www.example.org/address" xmlns:h="http://www.example.org/header">
<h:header>
<h:id>101</h:id>
</h:header>
<c:customer>
<c:id>1</c:id>
<c:name>Yen</c:name>
<a:address>
<a:street>Long street</a:street>
</a:address>
</c:customer>
<someBooSpecificField>Specific data in Boo</someBooSpecificField>
</xmlBoo>
for root element and its "simple" children is used default namespace (without prefix)
for complex (objects in java) children are used different namespaces (mapped to different prefixes)
model classes are in different packages
So here is the solution:
Define MOXy implementation of JAXB, file: jaxb.properties
javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory
Create abstract class for common fields, define namespace for object, file Xml.java
package example.xml;
#XmlTransient
public abstract class Xml {
private Header header;
private Customer customer;
#XmlElement(namespace="http://www.example.org/header")
public Header getHeader() {
return header;
}
public void setHeader(Header header) {
this.header = header;
}
#XmlElement(namespace="http://www.example.org/customer")
public Customer getCustomer() {
return customer;
}
public void setCustomer(Customer customer) {
this.customer = customer;
}
}
Create "root" class, XmlBoo.java
package example.xml.boo;
#XmlRootElement
#XmlType(propOrder = {"header", "customer", "someBooSpecificField"})
public class XmlBoo extends Xml {
private String someBooSpecificField;
// getter & setter
}
Set namespace and QUALIFIED for "root" class, file: example.xml.boo.package-info.java
#XmlSchema(
namespace = "http://www.example.org/boo",
elementFormDefault = XmlNsForm.QUALIFIED)
package example.xml.boo;
Set QUALIFIED to generate prefix for children (the namespace will be overridden by namespace defined on the class, but it must be defined), file: example.model.package-info.java
#XmlSchema(
namespace = "http://www.example.org",
elementFormDefault = XmlNsForm.QUALIFIED)
package example.model;
Create Header.java
package example.model;
#XmlType(namespace = "http://www.example.org/header")
public class Header {
private long id;
// getter & setter
}
Create Customer.java
package example.model;
#XmlType(namespace = "http://www.example.org/customer", propOrder = {"id", "name", "address"})
public class Customer {
private long id;
private String name;
private Address address;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#XmlElement(namespace="http://www.example.org/address")
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
}
Create Address.java
package example.model;
#XmlType(namespace = "http://www.example.org/address")
public class Address {
private String street;
// getter & setter
}
Create MyNamespacePrefixMapper.java by extending org.eclipse.persistence.oxm.NamespacePrefixMapper
package example;
import org.eclipse.persistence.oxm.NamespacePrefixMapper;
public class MyNamespacePrefixMapper extends NamespacePrefixMapper {
private static final String BOO_PREFIX = ""; // DEFAULT NAMESPACE
private static final String BOO_URI = "http://www.example.org/boo";
private static final String FOO_PREFIX = ""; // DEFAULT NAMESPACE
private static final String FOO_URI = "http://www.example.org/foo";
private static final String HEADER_PREFIX = "h";
private static final String HEADER_URI = "http://www.example.org/header";
private static final String CUSTOMER_PREFIX = "c";
private static final String CUSTOMER_URI = "http://www.example.org/customer";
private static final String ADDRESS_PREFIX = "a";
private static final String ADDRESS_URI = "http://www.example.org/address";
#Override
public String getPreferredPrefix(String namespaceUri, String suggestion, boolean requirePrefix) {
switch (namespaceUri) {
case BOO_URI:
return BOO_PREFIX;
case FOO_URI:
return FOO_PREFIX;
case HEADER_URI:
return HEADER_PREFIX;
case CUSTOMER_URI:
return CUSTOMER_PREFIX;
case ADDRESS_URI:
return ADDRESS_PREFIX;
default:
return null;
}
}
}
Create XML
public static void generateBoo() {
try {
JAXBContext jc = JAXBContext.newInstance(XmlBoo.class);
Marshaller m = jc.createMarshaller();
m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
m.setProperty(MarshallerProperties.NAMESPACE_PREFIX_MAPPER, new MyNamespacePrefixMapper());
XmlBoo xmlBoo = new XmlBoo();
Header header = new Header();
header.setId(101);
xmlBoo.setHeader(header);
Customer customer = new Customer();
customer.setId(1);
customer.setName("Yen");
Address address = new Address();
address.setStreet("Long street");
customer.setAddress(address);
xmlBoo.setCustomer(customer);
xmlBoo.setSomeBooSpecificField("Specific data in Boo");
m.marshal(xmlBoo, System.out);
m.marshal(xmlBoo, new File("xml_boo.xml"));
} catch (JAXBException e) {
e.printStackTrace();
}
}
Read XML
public static void readBoo() {
Object element = null;
try {
JAXBContext jc = JAXBContext.newInstance(XmlBoo.class);
Unmarshaller u = jc.createUnmarshaller();
element = u.unmarshal(new File("xml_boo.xml"));
} catch (JAXBException e) {
e.printStackTrace();
}
if (element instanceof XmlBoo) {
XmlBoo xmlBoo = (XmlBoo) element;
Customer customer = xmlBoo.getCustomer();
System.out.println("INFO | xmlBoo field: [" + xmlBoo.getSomeBooSpecificField() + "]");
System.out.println("INFO | customer name: [" + customer.getName() + "]");
System.out.println("INFO | address street: [" + customer.getAddress().getStreet() + "]");
}
}
I used EclipseLink MOXy JAXB implementation instead of RI Metro JAXB and now it works. So it looks that in Metro is bug.
Perfect tutorial by Blaise Doughan: JAXB & Namespace prefixes
You will need to have a package-info annotation with a #XmlSchema annotation for each package in your domain model each specifying the same namespace qualification to get the desired XML.
I have two inherited classes (ClassTop --> ClassChild) holding a data class each which have inherited properties too (ClassTopData --> ClassChildData):
ClassTop:
#XmlAccessorType(XmlAccessType.FIELD)
#XmlRootElement(name="root")
public class ClassTop {
#XmlElement(name="title")
private String title = null;
#XmlElement(name="meta")
private ClassTopData meta = new ClassTopData();
public String getTitle() {return title;}
public void setTitle(String title) {this.title = title;}
public ClassTopData getMeta() {return meta;}
public void setMeta(ClassTopData meta) {this.meta = meta;}
}
ClassChild extending ClassTop:
Important: ClassChild has the property meta as well but with an inherited variant of ClassTopData:
#XmlAccessorType(XmlAccessType.FIELD)
#XmlRootElement(name="news")
public class ClassChild extends ClassTop {
#XmlElement(name="childName")
private String childName = null;
#XmlElement(name="meta") // same property name...
private ClassChildData meta = new ClassChildData(); //... but subclassed data
public String getChildName() {return childName;}
public void setChildName(String childName) {this.childName = childName;}
public ClassChildData getMeta() {return meta;}
public void setMeta(ClassChildData meta) {this.meta = meta;}
}
And the two Data classes:
ClassTopData:
#XmlAccessorType(XmlAccessType.FIELD)
public class ClassTopData {
private String data1 = null;
private String data2 = null;
public String getData1() {return data1;}
public void setData1(String data1) {this.data1 = data1;}
public String getData2() {return data2;}
public void setData2(String data2) {this.data2 = data2;}
}
ClassChildData:
#XmlAccessorType(XmlAccessType.FIELD)
public class ClassChildData extends ClassTopData {
private String data3 = null;
public String getData3() {return data3;}
public void setData3(String data3) {this.data3 = data3;}
}
When I marshal the ClassChild and read it back, data3 is null:
ClassChild a = new ClassChild();
a.setTitle("title");
a.getMeta().setData1("1");
a.getMeta().setData2("2");
a.getMeta().setData3("3");
// Write:
JAXBContext context = JAXBContext.newInstance(ClassChild.class);
Marshaller m = context.createMarshaller();
m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
m.setProperty(Marshaller.JAXB_ENCODING, "UTF-8");
... get some OutputStream os ...
m.marshal(a, os);
// Read back:
JAXBContext jc = JAXBContext.newInstance(ClassChild.class);
Unmarshaller u = jc.createUnmarshaller();
... get the InputStream is ...
ClassChild r = (ClassChild)(u.unmarshal(is));
System.out.println("data3: "+r.getMeta().getData3());
And the output is
data3: null
The XML looks like this:
<?xml version="1.0" encoding="UTF-8"?>
<news>
<title>title</z:title>
<meta>
<data1>1</data1>
<data2>2</data2>
<data3>3</data3>
</meta>
</news>