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;
Related
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.
XML snippet:
<datasource formatted-name="blah" inline="blah">
<repository-location derived-from="blah" id="blah" path="blah" revision="blah" site="blah"/>
</datasource>
I am trying to unmarshal everything under one class (DataSource) with nested static classes. Here is my DataSource class:
#XmlRootElement(name = "datasource")
#XmlAccessorType(XmlAccessType.FIELD)
public class DataSource {
#XmlAttribute(name = "formatted-name")
protected String formattedName;
#XmlAttribute(name = "inline")
protected String inline;
#XmlElement(name = "repository-location")
protected RepositoryLocation repositoryLocation;
// public getters and setters for fields above
#XmlAccessorType(XmlAccessType.FIELD)
public static class RepositoryLocation {
#XmlAttribute(name = "derived-from")
protected String derivedFrom;
#XmlAttribute(name = "id")
protected String id;
#XmlAttribute(name = "path")
protected String path;
#XmlAttribute(name = "revision")
protected String revision;
#XmlAttribute(name = "site")
protected String site;
// public getters and setters for fields above
}
}
Unmarshaller:
JAXBContext jaxbContext = JAXBContext.newInstance(DataSource.class);
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
StringReader reader = new StringReader(responseXML);
dataSourceResponse = (DataSource) unmarshaller.unmarshal(reader);
I can successfully output DataSource fields "formattedName" and "inline", but "repositoryLocation" is null. Can someone help please?
JAXB is able to unmarshal without Getters/Setters and fields can even be private. Given the DataSource class above, having some generated toString method added to both DataSource and RepositoryLocation, the following prints out all properties:
import javax.xml.bind.*;
import javax.xml.bind.annotation.*;
import java.io.StringReader;
public class Jaxb {
public static void main(String[] args) throws JAXBException {
String xml = "<datasource formatted-name=\"blah\" inline=\"blah\">\n" +
" <repository-location derived-from=\"blah\" id=\"blah\"" +
" path=\"blah\" revision=\"blah\" site=\"blah\"/>\n" +
"</datasource>";
JAXBContext context = JAXBContext.newInstance(DataSource.class);
Unmarshaller unmarshaller = context.createUnmarshaller();
DataSource dataSource = (DataSource) unmarshaller.unmarshal(new StringReader(xml));
System.out.println(dataSource);
}
#XmlRootElement(name = "datasource")
#XmlAccessorType(XmlAccessType.FIELD)
private class DataSource {
#XmlAttribute(name = "formatted-name")
private String formattedName;
#XmlAttribute(name = "inline")
private String inline;
#XmlElement(name = "repository-location")
private RepositoryLocation repositoryLocation;
#XmlAccessorType(XmlAccessType.FIELD)
private class RepositoryLocation {
#XmlAttribute(name = "derived-from")
private String derivedFrom;
#XmlAttribute(name = "id")
private String id;
#XmlAttribute(name = "path")
private String path;
#XmlAttribute(name = "revision")
private String revision;
#XmlAttribute(name = "site")
private String site;
#Override
public String toString() {
return "RepositoryLocation{" +
"derivedFrom='" + derivedFrom + '\'' +
", id='" + id + '\'' +
", path='" + path + '\'' +
", revision='" + revision + '\'' +
", site='" + site + '\'' +
'}';
}
}
#Override
public String toString() {
return "DataSource{" +
"formattedName='" + formattedName + '\'' +
", inline='" + inline + '\'' +
", repositoryLocation=" + repositoryLocation +
'}';
}
}
}
Problem solved! I noticed my java 1.7 library is missing some jars. So I decided to go ahead upgrade to 1.8. It worked like magic!
Tried with java 1.7 too and it works and in xml.txt ,xml is saved
package testSingleJar.specificpackage;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.StringReader;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Unmarshaller;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
/**
* Hello world!
*
*/
public class App
{
public static void main( String[] args ) throws Exception
{
JAXBContext jaxbContext = JAXBContext.newInstance(DataSource.class);
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
String responseXML = "";
//filename is filepath string
BufferedReader br = new BufferedReader(new FileReader(new File("D:\\xml.txt")));
String line;
StringBuilder sb = new StringBuilder();
while((line=br.readLine())!= null){
sb.append(line.trim());
}
responseXML=sb.toString();
StringReader reader = new StringReader(responseXML);
DataSource dataSourceResponse = (DataSource) unmarshaller.unmarshal(reader);
System.out.println(dataSourceResponse.getRepositoryLocation().getDerivedFrom());
}
}
#XmlRootElement(name = "datasource")
#XmlAccessorType(XmlAccessType.FIELD)
class DataSource {
#XmlAttribute(name = "formatted-name")
protected String formattedName;
#XmlAttribute(name = "inline")
protected String inline;
#XmlElement(name = "repository-location")
protected RepositoryLocation repositoryLocation;
// public getters and setters for fields above
#XmlAccessorType(XmlAccessType.FIELD)
public static class RepositoryLocation {
#XmlAttribute(name = "derived-from")
protected String derivedFrom;
#XmlAttribute(name = "id")
protected String id;
#XmlAttribute(name = "path")
protected String path;
#XmlAttribute(name = "revision")
protected String revision;
#XmlAttribute(name = "site")
protected String site;
public String getDerivedFrom() {
return derivedFrom;
}
public void setDerivedFrom(String derivedFrom) {
this.derivedFrom = derivedFrom;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getPath() {
return path;
}
public void setPath(String path) {
this.path = path;
}
public String getRevision() {
return revision;
}
public void setRevision(String revision) {
this.revision = revision;
}
public String getSite() {
return site;
}
public void setSite(String site) {
this.site = site;
}
}
public String getFormattedName() {
return formattedName;
}
public void setFormattedName(String formattedName) {
this.formattedName = formattedName;
}
public String getInline() {
return inline;
}
public void setInline(String inline) {
this.inline = inline;
}
public RepositoryLocation getRepositoryLocation() {
return repositoryLocation;
}
public void setRepositoryLocation(RepositoryLocation repositoryLocation) {
this.repositoryLocation = repositoryLocation;
}
}
output : blah
This is the class I have:
#XmlRootElement(name = "XmlParent")
public class Foo {
private String name;
#XmlElement
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
and the sample xml file I have is as follows
<XmlParent>
<name>koraytugay</name>
</XmlParent>
Currently I can create an object from this file with the following code:
JAXBContext jaxbContext = JAXBContext.newInstance(Foo.class);
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
final FileReader fileReader = new FileReader(file);
final Foo foo = (Foo) unmarshaller.unmarshal(fileReader);
// foo.getName() will be koraytugay which is fine..
However, what I want to do is to be able to unmarshall the following xml file:
<XmlParent>
<name>koraytugay</name>
<bar>
<baz>
<qux>00000001</qux>
</baz>
</bar>
</XmlParent>
into the class:
#XmlRootElement(name = "XmlParent")
public class Foo {
private String name;
private String qux;
#XmlElement
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#XmlElement
public String getQux() {
return qux;
}
public void setQux(String qux) {
this.qux = qux;
}
}
So how can I bypass 'bar' and 'baz' while unmarshalling?
Depending on the actual structure of your XML and what you want to achieve.
Maybe using XPath could be an alternative way, if you need only few values from the XML input.
Find a small snippet below.
import java.io.ByteArrayInputStream;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathFactory;
import org.w3c.dom.Document;
...
String in = "<XmlParent>\n"
+ " <name>koraytugay</name>\n"
+ " <bar>\n"
+ " <baz>\n"
+ " <qux>00000001</qux>\n"
+ " </baz>\n"
+ " </bar>\n"
+ "</XmlParent>";
byte[] bytes = in.getBytes();
DocumentBuilder builder = DocumentBuilderFactory.newInstance()
.newDocumentBuilder();
Document document = builder.parse(new ByteArrayInputStream(bytes));
XPathFactory factory = XPathFactory.newInstance();
XPath xpath = factory.newXPath();
String name = xpath.evaluate("/XmlParent/name", document);
String qux = xpath.evaluate("/XmlParent/bar/baz/qux", document);
System.out.println("name = " + name);
System.out.println("qux = " + qux);
output
name = koraytugay
qux = 00000001
edit You could extend XMLEventReader and check on each event if it is a XML tag you want to skip.
The XML event reader.
import java.util.Set;
import javax.xml.namespace.QName;
import javax.xml.stream.XMLEventReader;
import javax.xml.stream.XMLStreamConstants;
import javax.xml.stream.XMLStreamException;
import javax.xml.stream.events.EndElement;
import javax.xml.stream.events.StartElement;
import javax.xml.stream.events.XMLEvent;
public class FilteringlXmlEventReader implements XMLEventReader {
final XMLEventReader reader;
final Set<QName> qNames;
public FilteringlXmlEventReader(XMLEventReader reader,
Set<QName> qNames) {
this.reader = reader;
this.qNames = qNames;
}
#Override
public XMLEvent nextEvent() throws XMLStreamException {
while (tagToSkip(reader.peek())) {
reader.nextEvent();
}
return reader.nextEvent();
}
// from XMLEventReader
#Override
public boolean hasNext() {
return reader.hasNext();
}
#Override
public XMLEvent peek() throws XMLStreamException {
return reader.peek();
}
#Override
public String getElementText() throws XMLStreamException {
return reader.getElementText();
}
#Override
public XMLEvent nextTag() throws XMLStreamException {
return reader.nextTag();
}
#Override
public Object getProperty(String name) throws IllegalArgumentException {
return reader.getProperty(name);
}
// from Iterator
#Override
public Object next() {
return reader.next();
}
#Override
public void remove() {
reader.remove();
}
#Override
public void close() throws XMLStreamException {
reader.close();
}
/**
* Check if the name of the XML tag which has triggered the passed
* event is to be skipped.
*
* #param event the current event
* #return {#code true} the event should be skipped, otherwise
* {#code false}
*/
private boolean tagToSkip(XMLEvent event) {
switch (event.getEventType()) {
case XMLStreamConstants.START_ELEMENT:
StartElement startTag = (StartElement) event;
return qNames.contains(startTag.getName());
case XMLStreamConstants.END_ELEMENT:
EndElement endTag = (EndElement) event;
return qNames.contains(endTag.getName());
}
return false;
}
}
The JAXB class.
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement(name = "XmlParent")
public class FooBar {
private String name;
private String qux;
#XmlElement
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#XmlElement
public String getQux() {
return qux;
}
public void setQux(String qux) {
this.qux = qux;
}
}
A example app to show the principle.
import java.io.ByteArrayInputStream;
import java.io.InputStream;
import java.util.HashSet;
import java.util.Set;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Unmarshaller;
import javax.xml.namespace.QName;
import javax.xml.stream.XMLEventReader;
import javax.xml.stream.XMLInputFactory;
import sub.optimal.xpath.FooBar;
public class FilteredUnmarshalling {
public static void main(String[] args) throws Exception {
String in = "<XmlParent>\n"
+ " <name>koraytugay</name>\n"
+ " <bar>\n"
+ " <baz>\n"
+ " <qux>00000001</qux>\n"
+ " </baz>\n"
+ " </bar>\n"
+ "</XmlParent>";
byte[] bytes = in.getBytes();
JAXBContext context = JAXBContext.newInstance(FooBar.class);
Unmarshaller unmarshaller = context.createUnmarshaller();
XMLInputFactory factory = XMLInputFactory.newInstance();
String[] tagNamesToFilter = {"bar", "baz"};
Set<QName> tagsToFilter = new HashSet<>();
for (String name : tagNamesToFilter) {
tagsToFilter.add(new QName(name));
}
try (InputStream reader = new ByteArrayInputStream(bytes)) {
XMLEventReader xmlEventReader=factory.createXMLEventReader(reader);
FooBar fooBar = (FooBar)unmarshaller.unmarshal(
new FilteringlXmlEventReader(xmlEventReader,tagsToFilter));
System.out.println("name: " + fooBar.getName());
System.out.println("qux : " + fooBar.getQux());
}
}
}
output
name: koraytugay
qux : 00000001
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();
}
}
}
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.