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>
Related
I have read other posts related to this issue but I could not fix my problem. I try to convert the following XML String to a JAVA class but when I try to access param1 using getParam1() method it returns null and I am not sure why.
The XML String:
<?xml version="1.0" encoding="utf-8"?>
<REQUERYTRXRESPONSE xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://tempuri.org/">
<param1>3gbahtJf1y85Oks4HrPLkqTQZV8Yg8pIhdXOrZ8pLGJP3FLwqKlIzIl/GgUpGvFaw4MC4SV+4pCudmVq+apIMIJJS4PrVyUx4T0ZO/Tsui4ZqCn62dLAG0DVhBVz2ZasF4yr7CRYnk47FWS0RywXmA==</param1>
<param2>lO4ismiJwsvBiHQGW/UwCA==</param2>
<param3 />
</REQUERYTRXRESPONSE>
The Java class:
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement(namespace = "http://tempuri.org/", name = "REQUERYTRXRESPONSE")
#XmlAccessorType(XmlAccessType.PROPERTY)
public class REQUERYTRXRESPONSE {
private String param1;
private String param2;
private String param3;
#XmlElement(required = true, name = "param1")
public String getParam1() {
return param1;
}
public void setParam1(String param1) {
this.param1 = param1;
}
#XmlElement(required = true, name = "param2")
public String getParam2() {
return param2;
}
public void setParam2(String param2) {
this.param2 = param2;
}
#XmlElement(required = true, name = "param3")
public String getParam3() {
return param3;
}
public void setParam3(String param3) {
this.param3 = param3;
}
}
The XML to Java class code:
HttpRequest httpRequest = HttpRequest.get();
if (httpRequest.ok()) {
String response = httpRequest.body();
System.out.println(response);
JAXBContext jaxbContext = JAXBContext.newInstance(REQUERYTRXRESPONSE.class);
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
REQUERYTRXRESPONSE requerytrxresponse = (REQUERYTRXRESPONSE) unmarshaller.unmarshal(new StringReader(response));
System.out.println((String) requerytrxresponse.getParam1()); // returns null
}
Managed to figure it out.
#XmlRootElement(name = "REQUERYTRXRESPONSE")
#XmlAccessorType(XmlAccessType.FIELD)
public class Response {
private String param1;
private String param2;
private String param3;
public String getParam1() {
return param1;
}
public void setParam1(String param1) {
this.param1 = param1;
}
public String getParam2() {
return param2;
}
public void setParam2(String param2) {
this.param2 = param2;
}
public String getParam3() {
return param3;
}
public void setParam3(String param3) {
this.param3 = param3;
}
}
You don't need to specify the #XmlElement when you do the #XxmlAccessorType unless you wanted the required=true part.
What I changed is that I moved the namespace from #XmlRootElement in a package-info.java class like so:
#javax.xml.bind.annotation.XmlSchema(namespace = "http://tempuri.org/",
elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED)
package com.sfatandrei.soplayground.model;
My main test method includes:
final InputStream resourceAsStream = SoPlaygroundApplication.class.getClassLoader().getResourceAsStream("test.xml");
JAXBContext jaxbContext = JAXBContext.newInstance(Response.class);
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
Response response = (Response) unmarshaller.unmarshal(resourceAsStream);
System.out.println(response);
For me it works just fine. Make sure that you've got a proper encoding and check your jaxb provider. I tested it with default sun implementation - com.sun.xml.bind.v2.runtime.JAXBContextImpl.
Make a test for your unmarshalling code:
#Test
public void testUnmarshaller() throws JAXBException, IOException {
final InputStream expectedXmlResource = getClass().getResourceAsStream("/REQUERYTRXRESPONSE.xml");
StringWriter stringWriter = new StringWriter();
IOUtils.copy(expectedXmlResource, stringWriter, "UTF-8");
JAXBContext jaxbContext = JAXBContext.newInstance(REQUERYTRXRESPONSE .class);
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
REQUERYTRXRESPONSE requerytrxresponse = (REQUERYTRXRESPONSE) unmarshaller.unmarshal(new StringReader(stringWriter.toString()));
assertEquals(requerytrxresponse.getParam1(), "3gbahtJf1y85Oks4HrPLkqTQZV8Yg8pIhdXOrZ8pLGJP3FLwqKlIzIl/GgUpGvFaw4MC4SV+4pCudmVq+apIMIJJS4PrVyUx4T0ZO/Tsui4ZqCn62dLAG0DVhBVz2ZasF4yr7CRYnk47FWS0RywXmA==");
}
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();
}
}
#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
From an XQuery performed by BaseX server I get a result like that:
<ProtocolloList>
<protocollo>
<numero>1</numero>
<data>2014-06-23</data>
<oggetto/>
<destinatario/>
<operatore/>
</protocollo>
...
</ProtocolloList>
And I need to convert this result in a List of Protocollo objects with JAXB so that I can show them with JList. Thus, following one of the discussions here I've declared the following classes:
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement(name = "protocollo")
public class Protocollo {
private int numero;
private String data;
private String oggetto;
private String destinatario;
private String operatore;
public Protocollo(String d, String o, String des, String op) {
this.data = d;
this.oggetto = o;
this.destinatario = des;
this.operatore = op;
}
public Protocollo() {
}
#XmlElement
public int getNumero() {
return numero;
}
public void setNumero(int numero) {
this.numero = numero;
}
#XmlElement
public String getData() {
return data;
}
public void setData(String data) {
this.data = data;
}
#XmlElement
public String getOggetto() {
return oggetto;
}
public void setOggetto(String oggetto) {
this.oggetto = oggetto;
}
#XmlElement
public String getDestinatario() {
return destinatario;
}
public void setDestinatario(String destinatario) {
this.destinatario = destinatario;
}
#XmlElement
public String getOperatore() {
return operatore;
}
public void setOperatore(String operatore) {
this.operatore = operatore;
}
}
and
import java.util.ArrayList;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement(name = "ProtocolloList")
public class ProtocolloList {
#XmlElementWrapper(name = "ProtocolloList")
#XmlElement(name = "protocollo")
private ArrayList<Protocollo> ProtocolloList;
public ArrayList<Protocollo> getProtocolloList() {
return ProtocolloList;
}
public void setProtocolloList(ArrayList<Protocollo> protocolloList) {
ProtocolloList = protocolloList;
}
}
and finally I execute the converion like that:
JAXBContext jaxbContext = JAXBContext.newInstance(Protocollo.class);
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
StringReader reader = new StringReader(this.resultXML);
protocolli = (ProtocolloList) unmarshaller.unmarshal(reader);
And I keep on getting this exception:
unexpected element (uri:"", local:"ProtocolloList"). Expected elements are <{}protocollo>
I suppose I'm making some mistakes with annotations.
Can you help?
For your use case you do not need the #XmlElementWrapper annotation. This is because the ProtocolList element corresponds to your #XmlRootElement annotation. Then you need the #XmlElement annotation on the property to grab each of the list items.
#XmlRootElement(name = "ProtocolloList")
public class ProtocolloList {
private ArrayList<Protocollo> ProtocolloList;
#XmlElement(name = "protocollo")
public ArrayList<Protocollo> getProtocolloList() {
return ProtocolloList;
}
}
Note:
By default you should annotate the property. If you want to annotate the fields you should put #XmlAccessorType(XmlAccessType.FIELD) on your class.
UPDATE
You need to make sure your JAXBContext is aware of the root class. You can change your JAXBContext creation code to be the following:
JAXBContext jaxbContext = JAXBContext.newInstance(ProtocolloList.class);
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