I am trying to unmarshal XML to java class as follows:-
My xml file as follows:-
<Features_res>
<StartWeek>202017</StartWeek>
<EndWeek>202035</EndWeek>
<Pno12>ABCDEEB</Pno12>
<FeatureList>
<Feature>
<Code>T002</Code>
</Feature>
<Feature>
<Code>T002</Code>
</Feature>
</FeatureList>
</Features_res>
Java InteriorResponse:-
#XmlRootElement(name = "Features_res")
public class InteriorResponse {
#XmlElement(name = "StartWeek")
private int sWeek;
#XmlElement(name = "EndWeek")
private int eWeek;
#XmlElement(name = "Pno12")
private String p12;
List<Feature> featureList;
public InteriorResponse() {
}
public InteriorResponse(int startWeek, int endWeek, String pno12) {
super();
this.sWeek = startWeek;
this.eWeek = endWeek;
this.p12 = pno12;
}
public int getStartWeek() {
return sWeek;
}
public void setStartWeek(int startWeek) {
this.sWeek = startWeek;
}
public int getEndWeek() {
return eWeek;
}
public void setEndWeek(int endWeek) {
this.eWeek = endWeek;
}
public String getPno12() {
return p12;
}
public void setPno12(String pno12) {
this.p12 = pno12;
}
public List<Feature> getFeatureList() {
return featureList;
}
#XmlElement(name = "FeatureList")
public void setFeatureList(List<Feature> featureList) {
this.featureList = featureList;
}
}
Another Java Feature:-
#XmlRootElement(name = "Feature")
public class Feature {
//#XmlElement(name = "Feature")
private String feature_;
#XmlElement(name = "code")
private String code_;
public String getCode() {
return code_;
}
public void setCode(String code) {
this.code_ = code;
}
public String getFeature_() {
return feature_;
}
public void setFeature_(String feature_) {
this.feature_ = feature_;
}
}
I am using above class as :-
public static void xmlToInterior() {
File file = new File("minxml.xml");
JAXBContext jaxbContext;
try {
jaxbContext = JAXBContext.newInstance(InteriorResponse.class);
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
InteriorResponse interiorFeatures = (InteriorResponse) unmarshaller.unmarshal(file);
List<Feature> list_feat = interiorFeatures.getFeatureList();
for(Feature ft : list_feat) {
System.out.println(ft.getCode());
}
} catch (JAXBException e) {
e.printStackTrace();
}
}
Output I have as:-
list_feat
code_ null
feature_ null
And list_feat has size 1. It should 2.
Also I have to name class member sWeek instead of startWeek. Otherwise, jaxbContext = JAXBContext.newInstance(InteriorResponse.class) throws exception like 2 element exist with same name.
XML additional part
I thought I could do the reaming part of the XML. I was trying part by part. But I couldn't do it. I really need to find some good tutorial or book about JXB. All I find a short overview of JXB. Any suggestion about where to read in details?
<Features_res>
<StartWeek>202017</StartWeek>
<EndWeek>202035</EndWeek>
<Pno12>ABCDEEB</Pno12>
<FeatureList>
<Feature>
<Code>T002</Code>
</Feature>
<Feature>
<Code>T002</Code>
</Feature>
</FeatureList>
<OptionList>
<Option>001048</Option>
<Option>000050</Option>
<Option>000790</Option>
</OptionList>
</Features_res>
So I made new class as:-
public class OptionList {
private List<Option> options;
#XmlElement(name = "Option")
public List<Option> getOptions() {
return options;
}
public void setOptions(List<Option> options) {
this.options = options;
}
}
Another class as :-
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlTransient;
public class Option {
#XmlElement(name = "Option")
private String option_;
public String getOption() {
return option_;
}
public void setOption(String option) {
this.option_ = option;
}
}
And updated for InteriorResponse class as:-
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement(name = "Features_res")
public class InteriorResponse {
#XmlElement(name = "StartWeek")
private int sWeek;
#XmlElement(name = "EndWeek")
private int eWeek;
#XmlElement(name = "Pno12")
private String p12;
private FeatureList featureList;
private OptionList optionList;
public InteriorResponse() {}
public InteriorResponse(int startWeek, int endWeek, String pno12) {
super();
this.sWeek = startWeek;
this.eWeek = endWeek;
this.p12 = pno12;
}
public int getStartWeek() {
return sWeek;
}
public void setStartWeek(int startWeek) {
this.sWeek = startWeek;
}
public int getEndWeek() {
return eWeek;
}
public void setEndWeek(int endWeek) {
this.eWeek = endWeek;
}
public String getPno12() {
return p12;
}
public void setPno12(String pno12) {
this.p12 = pno12;
}
#XmlElement(name = "FeatureList")
public FeatureList getFeatureList() {
return featureList;
}
public void setFeatureList(FeatureList featureList) {
this.featureList = featureList;
}
#XmlElement(name = "OptionList")
public OptionList getOptionList() {
return optionList;
}
public void setOptionList(OptionList optionList) {
this.optionList = optionList;
}
#Override
public String toString() {
return "InteriorResponse{"
+ "sWeek="
+ sWeek
+ ", eWeek="
+ eWeek
+ ", p12='"
+ p12
+ '\''
+ ", featureList="
+ featureList
+ '}';
}
}
I couldn't get the Option.
option null
The total xml is really huge. I still would like to try the remaing parts by myself part by part.
You need to design your classes according to XML structure. Find below the classes.
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement(name = "Features_res")
public class InteriorResponse {
#XmlElement(name = "StartWeek")
private int sWeek;
#XmlElement(name = "EndWeek")
private int eWeek;
#XmlElement(name = "Pno12")
private String p12;
private FeatureList featureList;
private OptionList optionList;
public InteriorResponse() {}
public InteriorResponse(int startWeek, int endWeek, String pno12) {
super();
this.sWeek = startWeek;
this.eWeek = endWeek;
this.p12 = pno12;
}
public int getStartWeek() {
return sWeek;
}
public void setStartWeek(int startWeek) {
this.sWeek = startWeek;
}
public int getEndWeek() {
return eWeek;
}
public void setEndWeek(int endWeek) {
this.eWeek = endWeek;
}
public String getPno12() {
return p12;
}
public void setPno12(String pno12) {
this.p12 = pno12;
}
#XmlElement(name = "FeatureList")
public FeatureList getFeatureList() {
return featureList;
}
public void setFeatureList(FeatureList featureList) {
this.featureList = featureList;
}
#XmlElement(name = "OptionList")
public OptionList getOptionList() {
return optionList;
}
public void setOptionList(OptionList optionList) {
this.optionList = optionList;
}
#Override
public String toString() {
return "InteriorResponse{"
+ "sWeek="
+ sWeek
+ ", eWeek="
+ eWeek
+ ", p12='"
+ p12
+ '\''
+ ", featureList="
+ featureList
+ ", optionList="
+ optionList
+ '}';
}
}
Class for Feature object
import javax.xml.bind.annotation.XmlElement;
public class Feature {
#XmlElement(name = "Code")
private String code_;
public String getCode() {
return code_;
}
public void setCode(String code) {
this.code_ = code;
}
#Override
public String toString() {
return "Feature{" + "code_='" + code_ + '\'' + '}';
}
}
Class for FeatureList
import javax.xml.bind.annotation.XmlElement;
import java.util.List;
public class FeatureList {
private List<Feature> features;
#XmlElement(name = "Feature")
public List<Feature> getFeatures() {
return features;
}
public void setFeatures(List<Feature> features) {
this.features = features;
}
}
Class for OptionList
import javax.xml.bind.annotation.XmlElement;
import java.util.List;
public class OptionList {
private List<String> option;
#XmlElement(name = "Option")
public List<String> getOption() {
return option;
}
public void setOption(List<String> option) {
this.option = option;
}
}
For testing and simplicity, I have written a small java test program below.
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import java.io.File;
import java.util.List;
public class Test {
public static void main(String[] args) {
File file =
new File("E:\\so\\xml\\minxml.xml");
JAXBContext jaxbContext;
try {
jaxbContext = JAXBContext.newInstance(InteriorResponse.class);
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
InteriorResponse interiorFeatures = (InteriorResponse) unmarshaller.unmarshal(file);
List<Feature> list_feat = interiorFeatures.getFeatureList().getFeatures();
List<String> optionList = interiorFeatures.getOptionList().getOption();
for (String option : optionList) {
System.out.println("Option Value : " + option);
}
for (Feature ft : list_feat) {
System.out.println(ft.getCode());
}
} catch (JAXBException e) {
e.printStackTrace();
}
}
}
I also provide the sample xml structure below.
<Features_res>
<StartWeek>202017</StartWeek>
<EndWeek>202035</EndWeek>
<Pno12>ABCDEEB</Pno12>
<FeatureList>
<Feature>
<Code>T002</Code>
</Feature>
<Feature>
<Code>T002</Code>
</Feature>
</FeatureList>
<OptionList>
<Option>001048</Option>
<Option>000050</Option>
<Option>000790</Option>
</OptionList>
</Features_res>
I knew very little about JAXB stuff. I have learned a lot from Sambit who helped a lot and gave me the way to start with this JAXB. Later I have implemented my version with less number of Java class and more smart use of JAXB annotations.
My version of InteriorResponse class:-
import java.util.List;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlTransient;
#XmlRootElement(name = "Features_res")
public class InteriorResponse {
#XmlElement(name = "StartWeek")
private int startWeek;
#XmlElement(name = "EndWeek")
private int endWeek;
#XmlElement(name = "Pno12")
private String pno12;
#XmlElementWrapper(name = "FeatureList")
#XmlElement(name = "Feature")
private List<Feature> featureList;
#XmlElementWrapper(name = "OptionList")
#XmlElement(name = "Option")
private List<String> optionList;
public InteriorResponse() {
}
public InteriorResponse(int startWeek, int endWeek, String pno12) {
super();
this.startWeek = startWeek;
this.endWeek = endWeek;
this.pno12 = pno12;
}
#XmlTransient
public int getStartWeek() {
return startWeek;
}
public void setStartWeek(int startWeek) {
this.startWeek = startWeek;
}
#XmlTransient
public int getEndWeek() {
return endWeek;
}
public void setEndWeek(int endWeek) {
this.endWeek = endWeek;
}
#XmlTransient
public String getPno12() {
return pno12;
}
public void setPno12(String pno12) {
this.pno12 = pno12;
}
#XmlTransient
public List<Feature> getFeatureList() {
return featureList;
}
public void setFeatureList(List<Feature> featureList) {
this.featureList = featureList;
}
#XmlTransient
public List<String> getOptionList() {
return optionList;
}
public void setOptionList(List<String> optionList) {
this.optionList = optionList;
}
#Override
public String toString() {
return "InteriorResponse{" + "sWeek=" + startWeek + ", eWeek=" + endWeek + ", pno12='" + pno12 + '\'' + ", featureList=" + featureList + ", optionList="
+ optionList + '}';
}
}
My version of Feature class:-
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlTransient;
public class Feature {
#XmlElement(name = "Code")
private String code;
#XmlTransient
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
#Override
public String toString() {
return "Feature{" + "code_='" + code + '\'' + '}';
}
}
Note that I don't need any extra wrapper class for FeatuerList and OptionList. It can be done by the JAXB annotation #XmlElementWrapper(name = "FeatureList"). Also, a very important lesson learned. We have to mark all the property's getter method as #XmlTransient. Otherwise, JAXB throws an exception 2 properties found with the same name. Because our class all properties is visible to the JAXB. So we have to mark one as #XmlTransient.
In my opion, it is a better solution than the accepted answer. I gave all the credit to Sambit. I hove this will help others.
Related
Java 1.8
Maven snippet:
<dependency>
<groupId>com.fasterxml.jackson.dataformat</groupId>
<artifactId>jackson-dataformat-xml</artifactId>
<version>2.11.2</version>
</dependency>
snipped.xml
<?xml version="1.0" standalone="no"?>
<ledesxml_snipped>
<lede_name>Fitzhume</lede_name>
<firm>
<lf_tax_id>999999999</lf_tax_id>
<lf_id>Cogswell Cogs</lf_id>
<lf_name>Cogswell Cogs, Inc.</lf_name>
<lf_address>
<address_info>
<address_1>404 Asteroid Drive</address_1>
<address_3>Suite 2600</address_3>
<city>Dallas</city>
<state_province>TX</state_province>
<zip_postal_code>75203</zip_postal_code>
<country>USA</country>
</address_info>
</lf_address>
<lf_billing_contact_phone>2145551212</lf_billing_contact_phone>
<lf_billing_contact_fax>2148761234</lf_billing_contact_fax>
<lf_billing_contact_email>bigcog#cogswellcogs.com</lf_billing_contact_email>
<source_app>AimPoint</source_app>
<app_version>
</app_version>
</firm>
</ledesxml_snipped>
LedesSnipped.java
package com.my.application.model;
import java.io.*;
import java.util.*;
import javax.xml.bind.annotation.*;
import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper;
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "", propOrder = {
"ledeName",
"firm"
})
#XmlRootElement(name = "ledesxml_snipped")
public class LedesxmlSnipped {
#XmlElement(name = "lede_name", required = true)
protected String ledeName;
#XmlElement(required = true)
#JacksonXmlElementWrapper( useWrapping = false)
protected LedesxmlSnipped.Firm firm;
public String getLedeName() {
return ledeName;
}
public void setLedName( String ledeName) {
this.ledeName = ledeName;
}
public LedesxmlSnipped.Firm getFirm() {
return firm;
}
public void setFirm(LedesxmlSnipped.Firm value) {
this.firm = value;
}
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "", propOrder = {
"lfTaxId",
"lfId",
"lfName",
"lfAddress",
"lfBillingContactPhone",
"lfBillingContactFax",
"lfBillingContactEmail",
"sourceApp",
"appVersion"
})
public static class Firm {
#XmlElement(name = "lf_tax_id")
protected int lfTaxId;
#XmlElement(name = "lf_id", required = true)
protected String lfId;
#XmlElement(name = "lf_name", required = true)
protected String lfName;
#XmlElement(name = "lf_address", required = true)
#JacksonXmlElementWrapper( useWrapping = false)
protected Ledesxml.Firm.LfAddress lfAddress;
#XmlElement(name = "lf_billing_contact_phone")
protected long lfBillingContactPhone;
#XmlElement(name = "lf_billing_contact_fax")
protected long lfBillingContactFax;
#XmlElement(name = "lf_billing_contact_email", required = true)
protected String lfBillingContactEmail;
#XmlElement(name = "source_app", required = true)
protected String sourceApp;
#XmlElement(name = "app_version", required = true)
protected String appVersion;
public int getLfTaxId() {
return lfTaxId;
}
public void setLfTaxId(int value) {
this.lfTaxId = value;
}
public String getLfId() {
return lfId;
}
public void setLfId(String value) {
this.lfId = value;
}
public String getLfName() {
return lfName;
}
public void setLfName(String value) {
this.lfName = value;
}
public Ledesxml.Firm.LfAddress getLfAddress() {
return lfAddress;
}
public void setLfAddress(Ledesxml.Firm.LfAddress value) {
this.lfAddress = value;
}
public long getLfBillingContactPhone() {
return lfBillingContactPhone;
}
public void setLfBillingContactPhone(long value) {
this.lfBillingContactPhone = value;
}
public long getLfBillingContactFax() {
return lfBillingContactFax;
}
public void setLfBillingContactFax(long value) {
this.lfBillingContactFax = value;
}
public String getLfBillingContactEmail() {
return lfBillingContactEmail;
}
public void setLfBillingContactEmail(String value) {
this.lfBillingContactEmail = value;
}
public String getSourceApp() {
return sourceApp;
}
public void setSourceApp(String value) {
this.sourceApp = value;
}
public String getAppVersion() {
return appVersion;
}
public void setAppVersion(String value) {
this.appVersion = value;
}
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "", propOrder = {
"addressInfo"
})
public static class LfAddress {
#XmlElement(name = "address_info", required = true)
protected Ledesxml.Firm.LfAddress.AddressInfo addressInfo;
public Ledesxml.Firm.LfAddress.AddressInfo getAddressInfo() {
return addressInfo;
}
public void setAddressInfo(Ledesxml.Firm.LfAddress.AddressInfo value) {
this.addressInfo = value;
}
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "", propOrder = {
"address1",
"address3",
"city",
"stateProvince",
"zipPostalCode",
"country"
})
public static class AddressInfo {
#XmlElement(name = "address_1", required = true)
protected String address1;
#XmlElement(name = "address_3", required = true)
protected String address3;
#XmlElement(required = true)
protected String city;
#XmlElement(name = "state_province", required = true)
protected String stateProvince;
#XmlElement(name = "zip_postal_code")
protected int zipPostalCode;
#XmlElement(required = true)
protected String country;
public String getAddress1() {
return address1;
}
public void setAddress1(String value) {
this.address1 = value;
}
public String getAddress3() {
return address3;
}
public void setAddress3(String value) {
this.address3 = value;
}
public String getCity() {
return city;
}
public void setCity(String value) {
this.city = value;
}
public String getStateProvince() {
return stateProvince;
}
public void setStateProvince(String value) {
this.stateProvince = value;
}
public int getZipPostalCode() {
return zipPostalCode;
}
public void setZipPostalCode(int value) {
this.zipPostalCode = value;
}
public String getCountry() {
return country;
}
public void setCountry(String value) {
this.country = value;
}
}
}
}
}
and lastly, TryThis.java
package com.my.application;
import java.util.*;
import java.io.*;
import java.time.*;
import java.time.format.*;
import javax.xml.stream.*;
import com.fasterxml.jackson.annotation.JsonInclude;
import com.fasterxml.jackson.core.JsonParseException;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.*;
import com.fasterxml.jackson.dataformat.xml.*;
import com.my.application.model.*;
public class TryThis {
public static void main(String[] args) {
XmlMapper mapper = new XmlMapper();
mapper.enable( SerializationFeature.INDENT_OUTPUT);
mapper.disable( DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
try {
File innFile = new File("snipped.xml");
LedesxmlSnipped asfda = mapper.readValue(innFile, LedesxmlSnipped.class);
System.out.println( "ledeName=" + asfda.getFirm().getLedeName());
} catch (JsonParseException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (JsonMappingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (FileNotFoundException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
the result of all this is just
ledeName=null
where I'd expect to see
ledeName=Fitzhume
No errors. So what am I missing? Some fiendishly subtle configuration? Am I defining XmlMapper in the wrong place? The many examples I've looked at span various versions of Jackson and some go back to using javax.xml.
Simply adding
import com.fasterxml.jackson.module.jaxb.JaxbAnnotationModule;
and
mapper.registerModule( new JaxbAnnotationModule());
to TryThis.java did the trick. Fiendishly subtle configuration issue indeed!
Thx to all who read the question.
I have very interesting xml and i am try to convert this xml to pojo. after my jaxb unmarshalling its return empty object.
here is xml:
<ServiceResultOfArrayOfstringuHEDJ7Dj xmlns:i="http://www.w3.org/2001/XMLSchema-instance" xmlns="http://schemas.datacontract.org/2004/07/HotelWeb.SanAdminSite.RestWebApi.App_Data">
<Data xmlns:d2p1="http://schemas.microsoft.com/2003/10/Serialization/Arrays">
<d2p1:string>1105</d2p1:string>
<d2p1:string>1111</d2p1:string>
</Data>
<Error>
<Code></Code>
<Message></Message>
</Error>
<InfoMessage></InfoMessage>
<IsSuccessful>true</IsSuccessful>
</ServiceResultOfArrayOfstringuHEDJ7Dj>
My POJO's :
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 = "ServiceResultOfArrayOfstringuHEDJ7Dj", namespace = "http://schemas.datacontract.org/2004/07/HotelWeb.SanAdminSite.RestWebApi.App_Data")
public class PostSendLogIdServiceXmlResult {
private String xmlns;
#XmlElement(name = "InfoMessage")
private String infoMessage;
#XmlElement(name = "Error")
private Error error;
#XmlElement(name = "Data")
private PostSendLogIdData data;
#XmlElement(name = "IsSuccessful")
private boolean isSuccessful;
public String getXmlns() {
return xmlns;
}
public void setXmlns(String xmlns) {
this.xmlns = xmlns;
}
public String getInfoMessage() {
return infoMessage;
}
public void setInfoMessage(String infoMessage) {
this.infoMessage = infoMessage;
}
public Error getError() {
return error;
}
public void setError(Error error) {
this.error = error;
}
public PostSendLogIdData getData() {
return data;
}
public void setData(PostSendLogIdData data) {
this.data = data;
}
public boolean isSuccessful() {
return isSuccessful;
}
public void setSuccessful(boolean successful) {
isSuccessful = successful;
}
#Override
public String toString() {
return "PostSendLogIdServiceXmlResult{" +
"xmlns='" + xmlns + '\'' +
", infoMessage='" + infoMessage + '\'' +
", error=" + error +
", data=" + data +
", isSuccessful=" + isSuccessful +
'}';
}
}
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(name = "Error")
#XmlAccessorType(XmlAccessType.FIELD)
public class PostSendLogIdError {
#XmlElement(name = "Code")
private String code;
#XmlElement(name = "Message")
private String message;
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
}
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import java.util.Arrays;
#XmlRootElement(name = "Data", namespace = "http://schemas.microsoft.com/2003/10/Serialization/Arrays")
#XmlAccessorType(XmlAccessType.FIELD)
public class PostSendLogIdData {
#XmlElement(name = "string")
private String[] postSendLogIds;
private String _xmlns;
public String[] getPostSendLogIds() {
return postSendLogIds;
}
public void setPostSendLogIds(String[] postSendLogIds) {
this.postSendLogIds = postSendLogIds;
}
public String get_xmlns() {
return _xmlns;
}
public void set_xmlns(String _xmlns) {
this._xmlns = _xmlns;
}
#Override
public String toString() {
return "PostSendLogIdData{" +
"postSendLogIds=" + Arrays.toString(postSendLogIds) +
", _xmlns='" + _xmlns + '\'' +
'}';
}
}
And My Jaxb converting implementation:
context = JAXBContext.newInstance(PostSendLogIdServiceXmlResult.class);
Unmarshaller unmarshaller = context.createUnmarshaller();
PostSendLogIdServiceXmlResult unmarshal = (PostSendLogIdServiceXmlResult) unmarshaller.unmarshal(new StringReader(response));
After this I'm getting new PostSendLogIdServiceXmlResult object with empty values.
Can you give me any advice.
Thanks in Advance.
Look at the XML again. The namespace is not applied to the <Data> element, it is applied to the <string> sub-elements. Notice where the d2p1: prefix is applied.
Also, the <Data> is not a root element, so the entire #XmlRootElement(name = "Data", ... annotation is unused, i.e. unnecessary, and it seems to be confusing you, so I recommend removing the annotation from the PostSendLogIdData class.
Correct use is:
#XmlElement(name = "string", namespace = "http://schemas.microsoft.com/2003/10/Serialization/Arrays")
private String[] postSendLogIds;
this is my xml structure
<catalog>
<course>
<course_id></course_id>
<subjects>
<subject>
<subject_id></subject_id>
</subject>
<subject>
<subject_id></subject_id>
</subject>
</subjects>
</course>
</catalog>
So, i'v tried to bind this xml to a class using JAXB Unmarshalling, but the result was nothing.
I was thinking, i have 2 base elements, course and subject, so i built 2 classes based on these elements.
This to control the course tag
#XmlRootElement(name="catalog")
#XmlAccessorType(XmlAccessType.FIELD)
public class curso {
#XmlElement(name="course_id")
int course_id;
#XmlElementWrapper(name="subjects")
#XmlElement(name="subject")
List <subject> subjects = new ArrayList<>();
public void setCourse_id(int curso_id) {
this.curso_id = curso_id;
}
public void setSubjects(List<subject> subjects) {
this.subjects = subjects;
}
}
And This to control the subject tag.
public class subject {
String subject_id;
#XmlElement(name="subject_id")
public void setSubjectId(String id) {
this.subject_id = id;
}
}
I made some to string functions, and my output was nothing.
What is the problem?
The course element also have a wrapper tag <course> So either you need to change you xml to remove <catalog> tag and make <course> as the root. Or you should create a new class catalog and make course as a field. Like
#XmlRootElement(name="catalog")
#XmlAccessorType(XmlAccessType.FIELD)
class catalog {
#XmlElement(name="course")
curso course;
public curso getCourse() {
return course;
}
public void setCourse(curso course) {
this.course = course;
}
#Override
public String toString() {
return "catalog [course=" + course + "]";
}
}
A complete example
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement(name="catalog")
#XmlAccessorType(XmlAccessType.FIELD)
class catalog {
#XmlElement(name="course")
curso course;
public curso getCourse() {
return course;
}
public void setCourse(curso course) {
this.course = course;
}
#Override
public String toString() {
return "catalog [course=" + course + "]";
}
}
class curso {
#XmlElement(name = "course_id")
int course_id;
#XmlElementWrapper(name = "subjects")
#XmlElement(name = "subject")
List<subject> subjects = new ArrayList<>();
public void setCourse_id(int curso_id) {
this.course_id = curso_id;
}
public void setSubjects(List<subject> subjects) {
this.subjects = subjects;
}
#Override
public String toString() {
return "curso [course_id=" + course_id + ", subjects=" + subjects + "]";
}
}
class subject {
String subject_id;
#XmlElement(name = "subject_id")
public void setSubjectId(String id) {
this.subject_id = id;
}
#Override
public String toString() {
return "subject [subject_id=" + subject_id + "]";
}
}
public class JaxbExample2 {
public static void main(String[] args) {
try {
File file = new File("file.xml");
JAXBContext jaxbContext = JAXBContext.newInstance(catalog.class);
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
catalog customer = (catalog) jaxbUnmarshaller.unmarshal(file);
System.out.println(customer);
} catch (JAXBException e) {
e.printStackTrace();
}
}
}
The xml structure I am trying to parse is:
<contentFiles>
<contentFile>
<fileNumbers>
<fileNumber>123<fileNumber>
</fileNumbers>
</contentFile>
<contentFile/>
<contentFiles>
How do I parse this using JAXB ?
I used the annotations on getters described above but I only get the last element in the multiples of FileNumbers saved. I want to save all the elements of FileNumbers in the list. How do I do this ?
EDIT:::
#XmlRootElement(name = "contentFiles")
public class RtSuperQuickMetadata
{
private List<RtSuperQuickMetadataItem> rtSuperQuickMetadataItems;
#XmlElement(name = "contentFile")
public final List<RtSuperQuickMetadataItem> getRtSuperQuickMetadataItems()
{
return rtSuperQuickMetadataItems;
}
// Setter
}
public class RtSuperQuickMetadataItem
{
private List<FileNumber> fileNumbers;
public RtSuperQuickMetadataItem()
{
fileNumbers = new ArrayList<FileNumber>();
}
#XmlElement(name = "fileNumbers")
public List<FileNumber> getFileNumbers()
{
return fileNumbers;
}
//setter
}
#XmlRootElement(name="fileNumber")
public class FileNumber
{
private String fileNumber;
/**
* Default no-arg constructor.
*/
public FileNumber()
{
// public no-arg constructor for JAXB
}
/**
* Accept a filenumber as constructor arg.
* #param fileNumber is the fileNumber
*/
public FileNumber(final String fileNumber)
{
this.fileNumber = fileNumber;
}
/**
* Getter.
* #return the fileNumber
*/
//#XmlElement(name = "fileNumber")
public final String getFileNumber()
{
return fileNumber;
}
/**
* Setter.
* #param fileNumber to be set.
*/
public final void setFileNumber(final String fileNumber)
{
this.fileNumber = fileNumber;
}
#Override
public final String toString()
{
return fileNumber;
}
}
The reason I'm asking for a larger XML file representation is that your code will completely depend on the requirements of the XML file. For instance, this bit of your code works with the following XML file:
Code:
import java.util.ArrayList;
import java.util.List;
import javax.xml.bind.annotation.*;
import javax.xml.bind.*;
public class JaxbTest {
private static final String RESOURCE_NAME = "data.txt";
public static void main(String[] args) {
// marshallTest();
unmarshallTest();
}
private static void unmarshallTest() {
JAXBContext context;
try {
context = JAXBContext.newInstance(RtSuperQuickMetadata.class);
Unmarshaller unmarshaller = context.createUnmarshaller();
RtSuperQuickMetadata metaData = (RtSuperQuickMetadata) unmarshaller
.unmarshal(JaxbTest.class.getResourceAsStream(RESOURCE_NAME));
System.out.println(metaData);
} catch (JAXBException e) {
e.printStackTrace();
}
}
private static void marshallTest() {
RtSuperQuickMetadata data = new RtSuperQuickMetadata();
List<RtSuperQuickMetadataItem> metaItemList = new ArrayList<RtSuperQuickMetadataItem>();
RtSuperQuickMetadataItem metaDataItem = new RtSuperQuickMetadataItem();
List<FileNumber> fileNumbers = new ArrayList<FileNumber>();
fileNumbers.add(new FileNumber("123"));
fileNumbers.add(new FileNumber("124"));
fileNumbers.add(new FileNumber("125"));
fileNumbers.add(new FileNumber("126"));
metaDataItem.setFileNumbers(fileNumbers);
metaItemList.add(metaDataItem);
data.setRtSuperQuickMetadataItems(metaItemList);
JAXBContext context;
try {
context = JAXBContext.newInstance(RtSuperQuickMetadata.class);
Marshaller marshaller = context.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(data, System.out);
} catch (JAXBException e) {
e.printStackTrace();
}
}
}
#XmlRootElement(name = "contentFiles")
class RtSuperQuickMetadata {
private List<RtSuperQuickMetadataItem> rtSuperQuickMetadataItems;
#XmlElement(name = "contentFile")
public final List<RtSuperQuickMetadataItem> getRtSuperQuickMetadataItems() {
return rtSuperQuickMetadataItems;
}
public void setRtSuperQuickMetadataItems(
List<RtSuperQuickMetadataItem> rtSuperQuickMetadataItems) {
this.rtSuperQuickMetadataItems = rtSuperQuickMetadataItems;
}
#Override
public String toString() {
return "RtSuperQuickMetadata [rtSuperQuickMetadataItems="
+ rtSuperQuickMetadataItems + "]";
}
}
class RtSuperQuickMetadataItem {
private List<FileNumber> fileNumbers;
public RtSuperQuickMetadataItem() {
fileNumbers = new ArrayList<FileNumber>();
}
#XmlElement(name = "fileNumbers")
public List<FileNumber> getFileNumbers() {
return fileNumbers;
}
public void setFileNumbers(List<FileNumber> fileNumbers) {
this.fileNumbers = fileNumbers;
}
#Override
public String toString() {
return "RtSuperQuickMetadataItem [fileNumbers=" + fileNumbers + "]";
}
}
#XmlRootElement(name = "fileNumber")
class FileNumber {
private String fileNumber;
public FileNumber() {}
public FileNumber(final String fileNumber) {
this.fileNumber = fileNumber;
}
// #XmlElement(name = "fileNumber")
public final String getFileNumber() {
return fileNumber;
}
public final void setFileNumber(final String fileNumber) {
this.fileNumber = fileNumber;
}
#Override
public final String toString() {
return fileNumber;
}
}
The xml file, assuming it's in the same directory as your class files:
jaxbTest.xml
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<contentFiles>
<contentFile>
<fileNumbers>
<fileNumber>123</fileNumber>
</fileNumbers>
<fileNumbers>
<fileNumber>124</fileNumber>
</fileNumbers>
<fileNumbers>
<fileNumber>125</fileNumber>
</fileNumbers>
<fileNumbers>
<fileNumber>126</fileNumber>
</fileNumbers>
</contentFile>
</contentFiles>
However if this is not your desired XML structure, then the code must change.
Edit
If you want to not nest each fileNumber element in a fileNumbers element, then get rid of the FileNumbers class and instead use a List<String> with the #XmlElementWrapper annotation.
#XmlElementWrapper(name = "fileNumbers")
#XmlElement(name = "fileNumber")
public List<String> getFileNumbers() {
return fileNumbers;
}
For instance please check out this code:
import java.util.ArrayList;
import java.util.List;
import javax.xml.bind.annotation.*;
import javax.xml.bind.*;
public class JaxbTest {
private static final String RESOURCE_NAME = "data.xml";
public static void main(String[] args) {
// marshallTest();
unmarshallTest();
}
private static void unmarshallTest() {
JAXBContext context;
try {
context = JAXBContext.newInstance(RtSuperQuickMetadata.class);
Unmarshaller unmarshaller = context.createUnmarshaller();
RtSuperQuickMetadata metaData = (RtSuperQuickMetadata) unmarshaller
.unmarshal(JaxbTest.class.getResourceAsStream(RESOURCE_NAME));
System.out.println(metaData);
} catch (JAXBException e) {
e.printStackTrace();
}
}
private static void marshallTest() {
RtSuperQuickMetadata data = new RtSuperQuickMetadata();
List<RtSuperQuickMetadataItem> metaItemList = new ArrayList<RtSuperQuickMetadataItem>();
RtSuperQuickMetadataItem metaDataItem = new RtSuperQuickMetadataItem();
// List<FileNumber> fileNumbers = new ArrayList<FileNumber>();
// fileNumbers.add(new FileNumber("123"));
// fileNumbers.add(new FileNumber("124"));
// fileNumbers.add(new FileNumber("125"));
// fileNumbers.add(new FileNumber("126"));
List<String> fileNumbers = new ArrayList<String>();
fileNumbers.add("123");
fileNumbers.add("124");
fileNumbers.add("125");
fileNumbers.add("126");
metaDataItem.setFileNumbers(fileNumbers);
metaItemList.add(metaDataItem);
data.setRtSuperQuickMetadataItems(metaItemList);
JAXBContext context;
try {
context = JAXBContext.newInstance(RtSuperQuickMetadata.class);
Marshaller marshaller = context.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(data, System.out);
} catch (JAXBException e) {
e.printStackTrace();
}
}
}
#XmlRootElement(name = "contentFiles")
class RtSuperQuickMetadata {
private List<RtSuperQuickMetadataItem> rtSuperQuickMetadataItems;
#XmlElement(name = "contentFile")
public final List<RtSuperQuickMetadataItem> getRtSuperQuickMetadataItems() {
return rtSuperQuickMetadataItems;
}
public void setRtSuperQuickMetadataItems(
List<RtSuperQuickMetadataItem> rtSuperQuickMetadataItems) {
this.rtSuperQuickMetadataItems = rtSuperQuickMetadataItems;
}
#Override
public String toString() {
return "RtSuperQuickMetadata [rtSuperQuickMetadataItems="
+ rtSuperQuickMetadataItems + "]";
}
}
class RtSuperQuickMetadataItem {
private List<String> fileNumbers;
public RtSuperQuickMetadataItem() {
fileNumbers = new ArrayList<String>();
}
#XmlElementWrapper(name = "fileNumbers")
#XmlElement(name = "fileNumber")
public List<String> getFileNumbers() {
return fileNumbers;
}
public void setFileNumbers(List<String> fileNumbers) {
this.fileNumbers = fileNumbers;
}
#Override
public String toString() {
return "RtSuperQuickMetadataItem [fileNumbers=" + fileNumbers + "]";
}
}
Will work with this XML:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<contentFiles>
<contentFile>
<fileNumbers>
<fileNumber>123</fileNumber>
<fileNumber>124</fileNumber>
<fileNumber>125</fileNumber>
<fileNumber>126</fileNumber>
</fileNumbers>
</contentFile>
</contentFiles>
It's been a while since I've done JAX-B but I think this should do the trick (only relevant sections posted). If you want to avoid creating the FileNumberList class you can probably do so with an adapter but that will be more work than it is worth.
public class RtSuperQuickMetadataItem {
#XmlElement
public FileNumberList getFileNumbers() {
}
}
public class FileNumberList {
#XmlElement(name="fileNumber")
public List<String> getList() {
}
}
I want to serialize a object hierarchy including a list of objects which derive from the base class 'Thing'. This works fine, including deserialization - but XML-Simple insists in writing an attribute which specifies the actual used Java-class
when I create a xml file with the java code below, the content is like this:
<example1>
<things>
<fruit class="com.mumpitz.simplexmltest.Apple" id="17">
<sugar>212</sugar>
</fruit>
<fruit class="com.mumpitz.simplexmltest.Orange" id="25" weight="11.2"/>
</things>
</example1>
but this is not what I want.
I'd like to have
<example1>
<things>
<apple id="17">
<sugar>212</sugar>
</apple>
<orange id="25" weight="11.2"/>
</things>
</example1>
'apple' and 'orange' elements without a class attribute, not 'fruit' with such an attribute. Is this possible?
(The second xml complies to a existing schema; adding extra attributes is not an option)
Here's the code:
package com.mumpitz.simplexmltest;
import java.io.File;
import java.util.ArrayList;
import org.simpleframework.xml.Attribute;
import org.simpleframework.xml.Element;
import org.simpleframework.xml.ElementList;
import org.simpleframework.xml.Root;
import org.simpleframework.xml.Serializer;
import org.simpleframework.xml.core.Persister;
class Fruit {
#Attribute(name = "id")
protected final int id;
Fruit(
#Attribute(name = "id")
int id) {
this.id = id;
}
int getObjectId() {
return id;
}
}
#Root
class Apple extends Fruit {
private final int sugar;
#Element(type = Fruit.class)
public Apple(
#Attribute(name = "id")
int id,
#Element(name = "sugar")
int sugar) {
super(id);
this.sugar = sugar;
}
#Element(name = "sugar")
public int getSugar() {
return this.sugar;
}
#Override
public String toString() {
return "id: " + id + ", sugar: " + sugar;
}
}
#Root
class Orange extends Fruit {
#Attribute
public double weight;
public Orange(
#Attribute(name = "id")
int id) {
super(id);
}
#Override
public String toString() {
return "id: " + id + ", weight: " + weight;
}
}
#Root
public class Example1 {
#ElementList
public ArrayList<Fruit> things = new ArrayList<Fruit>();
#Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("things:\n");
for (int i=0; i<things.size(); i++) {
sb.append(" " + things.get(i).toString() + "\n");
}
return sb.toString();
}
//////////////////////////////////
static Example1 createDummy() {
Example1 d = new Example1();
d.things.add(new Apple(17, 212));
Orange or = new Orange(25);
or.weight = 11.2;
d.things.add(or);
return d;
}
static String msg;
static Example1 res;
static public String getMessage() {
String m = msg;
msg = null;
return m;
}
static public boolean write(String path) {
Serializer serializer = new Persister();
Example1 example = Example1.createDummy();
File result = new File(path);
try {
serializer.write(example, result);
} catch (Exception e) {
e.printStackTrace();
msg = e.getMessage();
return false;
}
return true;
}
static public boolean read(String path) {
Serializer serializer = new Persister();
File source = new File(path);
try {
res = serializer.read(Example1.class, source);
} catch (Exception e) {
e.printStackTrace();
msg = e.getMessage();
return false;
}
return true;
}
public static Object getResult() {
return res;
}
}
some hours later I found the solution. You simply have to
Read the manual
Use the #ElementListUnion annotation
package com.mumpitz.simplexmltest;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import org.simpleframework.xml.Attribute;
import org.simpleframework.xml.Element;
import org.simpleframework.xml.ElementList;
import org.simpleframework.xml.ElementListUnion;
import org.simpleframework.xml.Root;
import org.simpleframework.xml.Serializer;
import org.simpleframework.xml.core.Persister;
// the base class
#Element
class Thing {
static int count=0;
Thing() {
this.id = ++count;
}
#Attribute
protected int id;
public int getId() {
return id;
}
}
// first derived class
#Element
class Car extends Thing {
#Attribute
private String name;
Car(#Attribute(name="name") String name) {
this.name = name;
}
public String getName() {
return name;
}
#Override
public String toString() {
return "ID: " + id + " Car: " + name;
}
}
// second derived class
#Element
class House extends Thing {
#Attribute
private int price;
House(#Attribute(name="price") int price) {
this.price = price;
}
public int getPrice() {
return this.price;
}
#Override
public String toString() {
return "ID: " + id + " House: " + price;
}
}
// a class with a list of base class instances
#Root(name="ListOfThings")
public class Example4 {
// specify the derived classes used in the list
#ElementListUnion({
#ElementList(entry="house", inline=true, type=House.class),
#ElementList(entry="car", inline=true, type=Car.class)
})
private ArrayList<Thing> list = new ArrayList<Thing>();
public void add(Thing t) {
list.add(t);
}
public List<Thing> getProperties() {
return list;
}
#Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("Example4 contains " + list.size() + " elements:\n");
for (Thing t : list) {
sb.append(" " + t.toString() + "\n");
}
return sb.toString();
}
//////////////////////////////////
// test code
//////////////////////////////////
static String msg;
static Example4 res;
static public String getMessage() {
String m = msg;
msg = null;
return m;
}
static private Example4 createDummy() {
Example4 d = new Example4();
d.add(new Car("Mercedes"));
d.add(new House(34000000));
d.add(new Car("VW"));
d.add(new House(230000));
return d;
}
//////////////////////////////////
// serialize / deserialize
//////////////////////////////////
static public boolean write(String path) {
Serializer serializer = new Persister();
File result = new File(path);
Example4 example = Example4.createDummy();
try {
serializer.write(example, result);
} catch (Exception e) {
e.printStackTrace();
msg = e.getMessage();
return false;
}
return true;
}
static public boolean read(String path) {
Serializer serializer = new Persister();
File source = new File(path);
try {
res = serializer.read(Example4.class, source);
} catch (Exception e) {
e.printStackTrace();
msg = e.getMessage();
return false;
}
return true;
}
public static Object getResult() {
return res;
}
}