When I try to unmarshal my Person.xml to a POJO and print it out the parent object prints out fine but ChildThree.java prints out null?
Test.java
public class Test {
public static void main(String[] args) {
try {
File file = new File("src/xml/person.xml");
System.out.println(file.getAbsolutePath());
JAXBContext jaxbContext = JAXBContext.newInstance(Parent.class);
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
Parent parent = (Parent) jaxbUnmarshaller.unmarshal(file);
System.out.println(parent);
} catch (JAXBException e) {
e.printStackTrace();
}
}
}
Person.xml
<?xml version="1.0" encoding="utf-8"?>
<Parent>
<ChildOne>1</Child>
<ChildTwo>2</Child>
<ChildThree>
<Name>3</Name>
<Age>Ten</Age>
</ChildThree>
</Parent>
Parent.java
#XmlRootElement(name = "Parent")
#XmlAccessorType(XmlAccessType.FIELD)
public class Parent {
#XmlElement
private String ChildOne;
#XmlElement
private String ChildTwo;
#XmlElement
private ChildThree ChildThree;
public String getChildOne() {
return ChildOne;
}
public void setChildOne() {
this.ChildOne = ChildOne;
}
public String getChildTwo() {
return ChildTwo;
}
public void setChildTwo() {
this.ChildTwo = ChildTwo;
}
public ChildThree getChildThree() {
return ChildThree;
}
public void setChildThree() {
this.ChildThree = ChildThree;
}
}
ChildThree.java
#XmlRootElement(name = "ChildThree")
#XmlAccessorType(XmlAccessType.FIELD)
public class ChildThree {
#XmlElement
private String Name;
#XmlElement
private String Age;
public String getName() {
return Name;
}
public void setName() {
this.Name = Name;
}
public String getAge() {
return Age;
}
public void setAge() {
this.Age = Age;
}
}
The following should help:
When you specify #XmlAccessorType(XmlAccessType.FIELD) on your class you should put your annotations on the field (instance variable) and not the property (get/set method), (see: http://blog.bdoughan.com/2011/06/using-jaxbs-xmlaccessortype-to.html).
Make sure your get/set methods follow the appropriate bean conventions:
String getFoo()
void setFoo(String)
Recognize that JAXB has rules for converting field/property names in Java to XML names that may differ from your expectations. When you have unmarshalling problems it is often useful to populate the object model and marshal it to see what JAXB is expecting (see: http://blog.bdoughan.com/2012/07/jaxb-no-annotations-required.html).
Fixed it by replacing:
#XmlElement
private ChildThree ChildThree;
with:
#XmlElement(name = "ChildThree")
private List<ChildThree> childThree;
Related
i have a xml and i want to save into a string the sub xml formed by the child of a specific tag.
this is a xml example:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<SampleDTO>
<id>1</id>
<someList>
<someObject>
<amount>32</amount>
<id>1</id>
<someDescription>I am a description</someDescription>
</someObject>
<someObject>
<amount>66</amount>
<id>2</id>
<someDescription>I am another description</someDescription>
</someObject>
<someObject>
<amount>78</amount>
<id>13</id>
<someDescription>Guess what? I am a description</someDescription>
</someObject>
</someList>
<otherList>
<otherObject>
<flag>true</flag>
<id>1</id>
<otherDescription>Oh nice, a description</otherDescription>
</otherObject>
</otherList>
</SampleDTO>
i want , passing for example "someList" , to save into a String the sub-xml element and value, because next i deserialize it into a java object
use the JAXB unmarshaller for converting xml document into java objects.
firstly add JAXB dependency into your project's classpath. for more info
SampleDTO.java
#XmlRootElement
public class SampleDTO {
private String id;
private List<SomeList> someList;
private List<OtherList> otherList;
#XmlElement
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
#XmlElement
public List<SomeList> getSomeList() {
return someList;
}
public void setSomeList(List<SomeList> someList) {
this.someList = someList;
}
#XmlElement
public List<OtherList> getOtherList() {
return otherList;
}
public void setOtherList(List<OtherList> otherList) {
this.otherList = otherList;
}
}
SomeList.java
#XmlRootElement
public class SomeList {
private List<SomeObject> someObject;
#XmlElement
public List<SomeObject> getSomeObject() {
return someObject;
}
public void setSomeObject(List<SomeObject> someObject) {
this.someObject = someObject;
}
}
OtherList.java
#XmlRootElement
public class OtherList {
private List<OtherObject> otherObject;
#XmlElement
public List<OtherObject> getOtherObject() {
return otherObject;
}
public void setOtherObject(List<OtherObject> otherObject) {
this.otherObject = otherObject;
}
}
SomeObject.java
#XmlRootElement
public class SomeObject {
private String amount;
private String id;
private String someDescription;
#XmlElement
public String getAmount() {
return amount;
}
public void setAmount(String amount) {
this.amount = amount;
}
#XmlElement
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
#XmlElement
public String getSomeDescription() {
return someDescription;
}
public void setSomeDescription(String someDescription) {
this.someDescription = someDescription;
}
}
OtherObject.java
#XmlRootElement
public class OtherObject {
private String flag;
private String id;
private String otherDescription;
#XmlElement
public String getFlag() {
return flag;
}
public void setFlag(String flag) {
this.flag = flag;
}
#XmlElement
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
#XmlElement
public String getOtherDescription() {
return otherDescription;
}
public void setOtherDescription(String otherDescription) {
this.otherDescription = otherDescription;
}
}
Unmarshalling with JAXB
public class Main {
public static void main(String[] args) {
try {
File file = new File("file.xml");
JAXBContext jaxbContext = JAXBContext.newInstance(SampleDTO.class);
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
SampleDTO sampleDTO= (SampleDTO) jaxbUnmarshaller.unmarshal(file);
} catch (JAXBException e) {
e.printStackTrace();
}
}
}
Your java class/object should have at least these 3 instance vars :
private int amount
private int id
private String description
Then use some xml parsing library (eg jdom2), and for each <someObject> tag you iterate through, initialize a new object of your class and assign to it the values parsed from the xml (amount / id / description) , and add each newly created object in a List or array etc..
There are many open-source XML processing packages available.
I like Jackson.
Here is a link to a Baeldung Article about Jackson XML
The summary is this:
Add a Jackson dependency to your POM.
Create an object structure that represents your xml structure.
Create an XmlMapper.
Use the XmlMapper.
I am having trouble unmarshalling a simple list of elements with JAXB. I have simplified my model further and still have a problem.
I have 2 element classes, a Classroom element and a Student element. I have modelled them in Java like below:
#XmlRootElement(name = "classroom", namespace = "http://www.info.com/school/model")
#XmlAccessorType(XmlAccessType.FIELD)
public class Classroom {
#XmlElementWrapper(name = "students")
#XmlElement(name = "student", type = Student.class)
private List<Student> students;
public List<Student> getStudents() {
return students;
}
public void setStudents(List<Student> students) {
this.students = students;
}
}
#XmlAccessorType(XmlAccessType.FIELD)
public class Student {
private String name;
private String gender;
private Integer age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getGender() {
return gender;
}
public void setGender(String gender) {
this.gender = gender;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
}
When I try to unmarshal the classroom element, it is unable to unmarshal the list of students. For example the following code should print out to System out "Number of Pupils is: 2", yet when I run it I get "Number of Pupils is: 0".
Is someone able to point me in the right direction for configuring the JAXB annotations so that I can unmarshal this?
I have even added a toString methof call on the JAXB context and I can see that the Student class is listed as well.
public static void main(String[] args) {
SimpleJaxbTestForLists sjtfl = new SimpleJaxbTestForLists();
sjtfl.unmarshal("<?xml version=\"1.0\" encoding=\"UTF-8\" standalone=\"yes\"?><classroom xmlns=\"http://www.info.com/school/model\"><students><student><name>Test Student 1</name><gender>Male</gender><age>12</age></student><student><name>Test Student 2</name><gender>Female</gender><age>12</age></student></students></classroom>");
}
public void unmarshal(String xmlContent) {
try {
JAXBContext jaxbContext = JAXBContext.newInstance(Classroom.class);
System.out.println(jaxbContext.toString());
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
StringReader reader = new StringReader(xmlContent);
Classroom classroom = (Classroom) jaxbUnmarshaller.unmarshal(reader);
System.out.println("Number of Pupils is: " + classroom.getStudents().size());
} catch (JAXBException ex) {
ex.printStackTrace();
}
}
Since your XML document specifies a default namespace, you can leverage a package level #XmlSchema annotation to map the namespace qualification:
package-info.java
#XmlSchema(
namespace = "http://www.info.com/school/model",
elementFormDefault = XmlNsForm.QUALIFIED)
package example;
import javax.xml.bind.annotation.XmlNsForm;
import javax.xml.bind.annotation.XmlSchema;
For More Information
You can read more about JAXB and namespace qualification on my blog:
http://blog.bdoughan.com/2010/08/jaxb-namespaces.html
In a personal project i have the following xml structures to make my own java classes:
first:
<response>
<action>getcredits</action>
<data>
<account>
<username>aptalaser</username>
<balance>193</balance>
</account>
</data>
second:
<response>
<action>getMsgInfoByID</action>
<data>
<messageid>c36d7ee5-16f9-4193-9a75-0537e590e9d3</messageid>
<originator>+17036231081 [4]</originator>
<recipient>10958</recipient>
<folder>INBOX</folder>
<senttime>2011.10.17 13:10:26</senttime>
<receivedtime>2011.10.17 13:10:26</receivedtime>
<creationtime>2011.10.17 13:10:26</creationtime>
<callbackid/>
<state>0</state>
<operatornames>
<operatorname>SMPP0</operatorname>
</operatornames>
<routes>
<route>defin_admin</route>
</routes>
<optionalfields>
<optionalfield name="30" value="35333131572D31303133322D303530364E2D333434544600"/>
<optionalfield name="8528" value="017F"/>
</optionalfields>
<messagetype>SMS:TEXT</messagetype>
<messagedata>Test message</messagedata>
</data>
third:
<response>
<action>sendmessage</action>
<data>
<acceptreport>
<statuscode>0</statuscode>
<statusmessage>Message accepted for delivery</statusmessage>
<messageid>0f06bbd9-0894-4fb4-9c4b-68e29363d299</messageid>
<originator>aptalaser</originator>
<recipient>8588430260</recipient>
<messagetype>SMS:TEXT</messagetype>
<messagedata>Bom dia cara.</messagedata>
</acceptreport>
</data>
The structures are divided in two places: a action to indicating the method acessed and the data section: a generic portion with will change the content dinamically in response to access a different method.
Following this idea i decide create a Response class with two field: a String action and a field Data:
The Response class:
/* omite desnecessary imports */
#XmlRootElement(name = "response")
#XmlAccessorType(XmlAccessType.PROPERTY)
public class Response {
private String action;
private Data data;
public String getAction() {
return action;
}
/* omitted set methds */
#XmlElementRef
public Data getData() {
return data;
}
#Override
public String toString() {
String template = "( action: %s, data: %s )";
return String.format(template, this.action, this.data);
}
}
The Data class, the base class for all Data sections
#XmlSeeAlso({ GetInfoMessageData.class, GetAccountData.class, SendMessageData.class })
public class Data {
}
The GetAccountClass to represent account retrieve information
/* omite desnecessary imports */
#XmlRootElement(name = "data")
#XmlAccessorType(XmlAccessType.PROPERTY)
public class GetAccountData extends Data {
private List<Account> account;
public List<Account> getAccount() {
return account;
}
/* omitted set methos */
#Override
public String toString() {
return String.format("Account( %s )", this.account);
}
public static class Account {
private String username;
private Long balance;
public String getUsername() {
return username;
}
public Long getBalance() {
return balance;
}
/* omitted set methods */
#Override
public String toString() {
return String.format("[ usr: %s, credit: %d ]", this.username, this.balance);
}
}
}
The class represents the message data
/* omite desnecessary imports */
#XmlRootElement(name = "data")
#XmlAccessorType(XmlAccessType.PROPERTY)
public class GetInfoMessageData extends Data {
private String messageId;
private String destino;
private String recipiente;
private String folder;
private Date dataCricao;
private Date dataEnvio;
private Date dataRecebimento;
private Integer status;
private String tipoMensagem;
private String mensagem;
private List<Protocolo> protocolos;
private List<Route> rotas;
private List<Field> optionalFields;
private Error error;
#XmlAccessorType(XmlAccessType.PROPERTY)
public static class Protocolo {
private String nomeProtocolo;
#XmlElement(name = "operatorname", defaultValue = "")
public String getNomeProtocolo() {
return nomeProtocolo;
}
/* omitted set methods */
}
#XmlAccessorType(XmlAccessType.PROPERTY)
public static class Error {
private String errorMessage;
#XmlElement(name = "errormessage")
public String getErrorMessage() {
return errorMessage;
}
/* omitted set methods */
}
#XmlAccessorType(XmlAccessType.PROPERTY)
public static class Route {
private String route;
#XmlElement(defaultValue = "")
public String getRoute() {
return route;
}
/* omitted set methods */
}
#XmlAccessorType(XmlAccessType.PROPERTY)
public static class Field {
private String name;
private String value;
#XmlAttribute
public String getName() {
return name;
}
#XmlAttribute
public String getValue() {
return value;
}
/* omitted set methods */
}
#XmlElement(name = "messageid", required = true)
public final String getMessageId() {
return messageId;
}
#XmlElement(name = "originator", required = true)
public final String getDestino() {
return destino;
}
#XmlElement(name = "recipient", defaultValue = "")
public final String getRecipiente() {
return recipiente;
}
#XmlElement(name = "folder", defaultValue = "")
public final String getFolder() {
return folder;
}
#XmlElement(name = "creationtime")
#XmlJavaTypeAdapter(type = Date.class, value = JavaDateAdapter.class)
public final Date getDataCricao() {
return dataCricao;
}
#XmlElement(name = "senttime")
#XmlJavaTypeAdapter(type = Date.class, value = JavaDateAdapter.class)
public final Date getDataEnvio() {
return dataEnvio;
}
#XmlElement(name = "receivedtime")
#XmlJavaTypeAdapter(type = Date.class, value = JavaDateAdapter.class)
public final Date getDataRecebimento() {
return dataRecebimento;
}
#XmlElement(name = "state", required = true)
public final Integer getStatus() {
return status;
}
#XmlElement(name = "messagetype", required = true)
public final String getTipoMensagem() {
return tipoMensagem;
}
#XmlElement(name = "messagedata")
public final String getMensagem() {
return mensagem;
}
#XmlElement(name = "operatornames")
public final List<Protocolo> getProtocolos() {
return protocolos;
}
#XmlElement(name = "routes")
public final List<Route> getRotas() {
return rotas;
}
#XmlElement(name = "optionalfield")
#XmlElementWrapper(name = "optionalfields")
public List<Field> getOptionalFields() {
return optionalFields;
}
#XmlElement(name = "error")
public Error getError() {
return error;
}
/* omitted set methods */
}
The class represent the sendMessage response operation
/* omite desnecessary imports */
#XmlRootElement(name = "data")
#XmlAccessorType(XmlAccessType.PROPERTY)
public class SendMessageData extends Data {
private AcceptReport acceptReport;
#XmlElement(name = "acceptreport")
public AcceptReport getAcceptReport() {
return acceptReport;
}
#SuppressWarnings("unused")
public void setAcceptReport(AcceptReport acceptReport) {
this.acceptReport = acceptReport;
}
#Override
public String toString() {
return String.format("Report( %s )", this.acceptReport);
}
#XmlRootElement(name = "acceptreport")
public static class AcceptReport {
private Integer status;
private String statusMessage;
private String messageId;
private String originator;
private String recipient;
private String messageType;
private String messageData;
#XmlElement(name = "statuscode")
public Integer getStatus() {
return status;
}
#XmlElement(name = "statusmessage")
public String getStatusMessage() {
return statusMessage;
}
#XmlElement(name = "messageid")
public String getMessageId() {
return messageId;
}
#XmlElement(name = "originator")
public String getOriginator() {
return originator;
}
#XmlElement(name = "recipient")
public String getRecipient() {
return recipient;
}
#XmlElement(name = "messagetype")
public String getMessageType() {
return messageType;
}
#XmlElement(name = "messagedata")
public String getMessageData() {
return messageData;
}
/* set methods omited */
#Override
public String toString() {
return String.format("[ stats: %d, msgId: %s, msg: %s ]", this.status, this.messageId, this.messageData);
}
}
}
The xml 'data' section don't have anything to identifing 'what son of Data will be use in the ummarshaling operation?'
My test works fine in the marshalling operation but in the ummarshalling its broken because the jaxb don't identify the son of Data to use.
/* omite desnecessary imports */
public class Teste {
public static void main(String[] args) throws JAXBException {
JAXBContext ctx = JAXBContext.newInstance(
Data.class, GetAccountData.class,
GetInfoMessageData.class, Response.class, SendMessageData.class
);
Marshaller marshaller = ctx.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
Response r = new Response();
r.setAction("getcredits");
GetAccountData data = new GetAccountData();
Account account = new GetAccountData.Account();
account.setUsername("aptalaser");
account.setBalance(12523L);
data.setAccount(Arrays.asList(account));
r.setData(data);
//in there is equal to first xml
marshaller.marshal(r, System.out);
Unmarshaller unmarshaller = ctx.createUnmarshaller();
Response resp = (Response) unmarshaller.unmarshal(new File("./get-credits.xml"));
//but in there the resp retrieved is to the third xml(and the Data field is null)
System.out.println(resp);
}
}
The question is: I need implement my own customized converter or i can make that with simple configurations like annotations?
Thanks for help.
For the purposes of unmarshalling you need to have a unique identifier that can be used to identify the appropriate subclass to instantiate.
#XmlElementRef
Since you are using #XmlElementRef this unique identifier should be the #XmlRootElement of the subclass, but you currently have all subclasses with #XmlRootElement(name="data").
http://blog.bdoughan.com/2010/11/jaxb-and-inheritance-using-substitution.html
xsi:type Attribute
If you want to always leverage the data element then you need something else as the inheritance indicator. If you remove the #XmlElementRef annotation then JAXB will leverage the xsi:type attribute for this purpose.
http://blog.bdoughan.com/2010/11/jaxb-and-inheritance-using-xsitype.html
Element Content
If neither of the above will work for you then you can leverage an XmlAdapter.
http://blog.bdoughan.com/2012/01/jaxb-and-inhertiance-using-xmladapter.html
UPDATE
Thank you #Blaise this help me so much, one more thing: i need process
this model, so i need implement different response class with
appropriate subclass field?
If you know which type of response you are receiving this is a valid approach. Then when you do the unmarshal you can specify the class you are unmarshalling. You will need to do this because the response root element corresponds to all the response classes you will make.
GetAccountDataResponse = unmarshaller.unmarshal(xml, GetAccountDataResponse.class).getValue();
If you don't know what type of response you are receiving and need to decide based on the content of the message then an XmlAdapter approach for handling inheritance will work.
http://blog.bdoughan.com/2012/01/jaxb-and-inhertiance-using-xmladapter.html
Hopefully an easy one for JAXB experts:
I am trying to marshal an immutable class that does not define a default no-arg constructor. I have defined an XmlAdapter implementation but it doesn't seem to be picked up. I have put together a simple self-contained example, which is still failing to work. Can anyone advise what I'm doing wrong?
Immutable Class
#XmlJavaTypeAdapter(FooAdapter.class)
#XmlRootElement
public class Foo {
private final String name;
private final int age;
public Foo(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() { return name; }
public int getAge() { return age; }
}
Adapter and Value Type
public class FooAdapter extends XmlAdapter<AdaptedFoo, Foo> {
public Foo unmarshal(AdaptedFoo af) throws Exception {
return new Foo(af.getName(), af.getAge());
}
public AdaptedFoo marshal(Foo foo) throws Exception {
return new AdaptedFoo(foo);
}
}
class AdaptedFoo {
private String name;
private int age;
public AdaptedFoo() {}
public AdaptedFoo(Foo foo) {
this.name = foo.getName();
this.age = foo.getAge();
}
#XmlAttribute
public String getName() { return name; }
public void setName(String name) { this.name = name; }
#XmlAttribute
public int getAge() { return age; }
public void setAge(int age) { this.age = age; }
}
Marshaller
public class Marshal {
public static void main(String[] args) {
Foo foo = new Foo("Adam", 34);
try {
JAXBContext jaxbContext = JAXBContext.newInstance(Foo.class);
Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
// output pretty printed
jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
jaxbMarshaller.marshal(foo, System.out);
} catch (JAXBException e) {
e.printStackTrace();
}
}
}
Stack Trace
com.sun.xml.internal.bind.v2.runtime.IllegalAnnotationsException: 1 counts of IllegalAnnotationExceptions
Foo does not have a no-arg default constructor.
this problem is related to the following location:
at Foo
at com.sun.xml.internal.bind.v2.runtime.IllegalAnnotationsException$Builder.check(IllegalAnnotationsException.java:91)
at com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl.getTypeInfoSet(JAXBContextImpl.java:451)
at com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl.<init>(JAXBContextImpl.java:283)
at com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl.<init>(JAXBContextImpl.java:126)
at com.sun.xml.internal.bind.v2.runtime.JAXBContextImpl$JAXBContextBuilder.build(JAXBContextImpl.java:1142)
at com.sun.xml.internal.bind.v2.ContextFactory.createContext(ContextFactory.java:130)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:601)
at javax.xml.bind.ContextFinder.newInstance(ContextFinder.java:248)
at javax.xml.bind.ContextFinder.newInstance(ContextFinder.java:235)
at javax.xml.bind.ContextFinder.find(ContextFinder.java:445)
at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:637)
at javax.xml.bind.JAXBContext.newInstance(JAXBContext.java:584)
at Marshal2.main(Marshal2.java:11)
Note that I am using JDK 1.7.0_05.
The following should help:
FOO AS ROOT OBJECT
When #XmlJavaTypeAdapter is specified at the type level it only applies to fields/properties referencing that class, and not when an instance of that class is a root object in your XML tree. This means that you will have to convert Foo to AdaptedFoo yourself, and create the JAXBContext on AdaptedFoo and not Foo.
Marshal
package forum11966714;
import javax.xml.bind.*;
public class Marshal {
public static void main(String[] args) {
Foo foo = new Foo("Adam", 34);
try {
JAXBContext jaxbContext = JAXBContext.newInstance(AdaptedFoo.class);
Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
// output pretty printed
jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
jaxbMarshaller.marshal(new AdaptedFoo(foo), System.out);
} catch (JAXBException e) {
e.printStackTrace();
}
}
}
AdaptedFoo
You will need to add an #XmlRootElement annotation to the AdaptedFoo class. You can remove the same annotation from the Foo class.
package forum11966714;
import javax.xml.bind.annotation.*;
#XmlRootElement
class AdaptedFoo {
private String name;
private int age;
public AdaptedFoo() {
}
public AdaptedFoo(Foo foo) {
this.name = foo.getName();
this.age = foo.getAge();
}
#XmlAttribute
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#XmlAttribute
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
FOO AS NESTED OBJECT
When Foo isn't the root object everything works the way you have it mapped. I have extended your model to demonstrate how this would work.
Bar
package forum11966714;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement
public class Bar {
private Foo foo;
public Foo getFoo() {
return foo;
}
public void setFoo(Foo foo) {
this.foo = foo;
}
}
Demo
Note that the JAXB reference implementation will not let you specify the Foo class when bootstrapping the JAXBContext.
package forum11966714;
import java.io.File;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
public class Demo {
public static void main(String[] args) {
try {
JAXBContext jaxbContext = JAXBContext.newInstance(Bar.class);
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
File xml = new File("src/forum11966714/input.xml");
Bar bar = (Bar) jaxbUnmarshaller.unmarshal(xml);
Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
jaxbMarshaller.marshal(bar, System.out);
} catch (JAXBException e) {
e.printStackTrace();
}
}
}
input.xml/Output
<?xml version="1.0" encoding="UTF-8"?>
<bar>
<foo name="Jane Doe" age="35"/>
</bar>
I know that this is not the case, but if you have such an error when you put #XmlJavaTypeAdapter for the field - check that you specified the namespace. You may need it.
In my case this didn't work:
#XmlElement(name = "Expiration")
#XmlJavaTypeAdapter(DateAdapter.class)
private Date expiration;
until a namespace has been specified:
#XmlElement(name = "Expiration", namespace="http://site/your.namespace")
#XmlJavaTypeAdapter(DateAdapter.class)
private Date expiration;
This is my Parser class
public class Test {
public static void main(String args[]) throws Exception {
File file = new File("D:\\Test.xml");
JAXBContext jaxbContext = JAXBContext.newInstance(MyOrder.class);
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
MyOrder customer = (MyOrder) jaxbUnmarshaller.unmarshal(file);
System.out.println(customer.getOrder().getSide());
}
}
This is MyOrder.java file
#XmlRootElement(name = "BXML")
public class MyOrder {
#XmlElement(name = "Bag")
protected Order order;
public MyOrder() {
}
#XmlAttribute
public Order getOrder() {
return order;
}
public void setOrder(Order order) {
this.order = order;
}
}
This is my Domain Object (Order.java )
#XmlRootElement(name = "BXML")
public class Order {
public Order() {
}
#XmlAttribute(name = "Side")
protected BigInteger Side;
#XmlValue
public BigInteger getSide() {
return Side;
}
public void setSide(BigInteger side) {
Side = side;
}
}
This is the exception that I am getting when I tried to run the program
Exception in thread "main" com.sun.xml.internal.bind.v2.runtime.IllegalAnnotationsException: 2 counts of IllegalAnnotationExceptions
#XmlAttribute/#XmlValue need to reference a Java type that maps to text in XML.
this problem is related to the following location:
at public com.Order com.MyOrder.getOrder()
at com.MyOrder
Class has two properties of the same name "order"
this problem is related to the following location:
at public com.Order com.MyOrder.getOrder()
at com.MyOrder
this problem is related to the following location:
at protected com.Order com.MyOrder.order
at com.MyOrder
For the #XmlAttribute/#XmlValue need to reference a Java type that maps to text in XML. issue you need to change your initialization of JAXBContext to the following:
JAXBContext jaxbContext = JAXBContext.newInstance(MyOrder.class, Order.class);
For the Class has two properties of the same name "order" issue, you need to change the definition of protected Order order; to private Order order;.
Also, you want to change the #XmlRootElement(name = "BXML") of your Order class to #XmlRootElement(name = "Order").
You can see the below sample code to generate Java Object from given XML.It is working fine in my system.
customer.xml
<?xml version="1.0" encoding="UTF-8"?>
<company>
<customer id="100">
<age>25</age>
<name>Ram</name>
<Address>
<city>Bangalore</city>
<country>India</country>
</Address>
<Address>
<city>Patna</city>
<country>India</country>
</Address>
</customer>
<customer id="200">
<age>26</age>
<name>Ashu</name>
<Address>
<city>Delhi</city>
<country>India</country>
</Address>
<Address>
<city>Madhubani</city>
<country>India</country>
</Address>
</customer>
</company>
Company.java
import java.util.List;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
#XmlAccessorType(XmlAccessType.FIELD)
#XmlRootElement(name="company")
public class Company {
#XmlElement(name="customer")
private List<Costumer> custList;
//
public List<Costumer> getCustList() {
return custList;
}
public void setCustList(List<Costumer> custList) {
this.custList = custList;
}
//
#Override
public String toString() {
return "Company [custList=" + custList + "]";
}
}
Costumer.java
#XmlAccessorType(XmlAccessType.FIELD)
class Costumer {
#XmlElement(name="name")
private String name;
#XmlElement(name="age")
private int age;
#XmlElement(name="id")
private int id;
#XmlElement(name="Address")
private List<Address> addressList;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public List<Address> getAddressList() {
return addressList;
}
public void setAddressList(List<Address> addressList) {
this.addressList = addressList;
}
#Override
public String toString() {
return "Customer [name=" + name + ", age=" + age + ", id=" + id + ", addressList=" + addressList + "]";
}
}
Address.java
#XmlAccessorType(XmlAccessType.FIELD)
class Address {
#XmlElement(name="city")
private String city;
#XmlElement(name="country")
private String country;
//
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public String getCountry() {
return country;
}
public void setCountry(String country) {
this.country = country;
}
//
#Override
public String toString() {
return "Address [city=" + city + ", country=" + country + "]";
}
}
TestMain.java
import java.io.File;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
public class TestMain {
public static void main(String[] args) {
String xmlPath = "C:\\" + File.separator + "customer.xml";
try {
File file = new File(xmlPath);
JAXBContext jaxbContext = JAXBContext.newInstance(new Class[] {Company.class,Address.class,Costumer.class});
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
Company customer = (Company) jaxbUnmarshaller.unmarshal(file);
System.out.println(customer);
} catch (JAXBException e) {
e.printStackTrace();
}
}
}
Outout:
Company [custList=[Customer [name=Ram, age=25, id=0, addressList=[Address [city=Bangalore, country=India], Address [city=Patna, country=India]]], Customer [name=Ashu, age=26, id=0, addressList=[Address [city=Delhi, country=India], Address [city=Madhubani, country=India]]]]]
This is because the sub-elements of that class you are creating JAXBcontext instance ,doesn't have the same name as of the element names defined inside it.
Example:
#XmlType(name = "xyz", propOrder = { "a", "b", "c", "d" })
#XmlRootElement(name = "testClass")
public class TestClass
{
#XmlElement(required = true)
protected Status status;
#XmlElement(required = true)
protected String mno;
#XmlElement(required = true)
}
In the above class you don't have "xyz" , but if you will put the property name that is not available JAXBContext instantiation throws IlligalAnnotationException.
If anyone is curious about the usage of JAXB and Lombok.
My fix was to remove the getter and setter from the root object.