Unmarshalling xml to modal class failed using JAXB in java - java

I am trying to map this xml into my modal class using JAXB. I have searched many solutions. But somehow for this one nothing is working. Everytime on mapping this xml to my model class I am getting
1 counts of IllegalAnnotationExceptions
<body>
<i>
<f name="name">test name</f>
<f name="address">test address</f>
<f name="phone">test phone</f>
</i>
</body>
This is my model class
#XmlRootElement(name = "body")
public class body {
// XmLElementWrapper generates a wrapper element around XML representation
#XmlElementWrapper(name = "i")
// XmlElement sets the name of the entities
#XmlElement(name = "f")
private ArrayList<f> f;
public ArrayList<f> getF() {
return f;
}
public void setF(ArrayList<f> f) {
this.f = f;
}
#XmlRootElement(name = "f")
public static class f {
String name;
public String getName() {
return name;
}
#XmlAttribute(name = "name")
public void setName(String name) {
this.name = name;
}
}
}
This is how i am simply accessing:
InputSource inputSource = new InputSource(new StringReader(inputXml));
// map xml to model class in jaxb
JAXBContext jaxbContext = JAXBContext.newInstance(Modal.class);
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
Modal modal = (Modal) jaxbUnmarshaller.unmarshal(inputSource);
What am I missing? And further is there a way to access value of "f" node? Thanks.

Related

Unmarshal element attribute and text to separate fields with jaxb

How do I annotate the externalValue and companyId fields in the Root class so that "abc" gets mapped to externalValue and "123" gets mapped to companyId?
Do I need the #XmlJavaTypeAdapter annotation? Where? I'm hoping that if I do, it can just handle those 2 fields and I can leave the annotations for title and countryCodes as-is.
XML:
<item>
<externalValue companyId="123">abc</externalValue>
<title>My Title</title>
<country>US</country>
<country>CA</country>
</item>
POJO:
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class Item {
private String externalValue;
private String companyId;
#XmlElement
private String title;
#XmlElement(name = "country")
public List<String> countryCodes;
// getters and setters...
}
I am afraid that this is not possible to achieve only with annotations (so without extra POJO and some adapter) in general case namely JAXB specs. However if your happen to use MOXy as your JAXB implementation it is easy as adding annotation #XmlPath like this:
#XmlPath("externalValue/#companyId")
private String companyId;
Related question: Unmarshalling an XML using Xpath expression and jaxb
You have to define the class in the following manner.
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class Item {
private CompanyIdValue companyIdValue;
#XmlElement
private String title;
#XmlElement(name = "country")
public List<String> countryCodes;
//getter and setter
}
In case of both attribute in an XML element tag, you have to define a separate class. Define a separate class called CompanyIdValue, for XML element, you have to define #XmlValue and for attribute you have to annotate with #XmlAttribute
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlValue;
public class CompanyIdValue {
#XmlElement(name = "externalValue")
private String externalValue;
private String companyId;
public String getExternalValue() {
return externalValue;
}
#XmlValue
public void setExternalValue(String externalValue) {
this.externalValue = externalValue;
}
public String getCompanyId() {
return companyId;
}
#XmlAttribute
public void setCompanyId(String companyId) {
this.companyId = companyId;
}
}
I provide below a test program also for testing.
public class Test {
public static void main(String[] args) {
try {
Item item = new Item();
CompanyIdValue companyIdValue = new CompanyIdValue();
companyIdValue.setCompanyId("SomeId");
companyIdValue.setExternalValue("Some External value");
item.setCompanyIdValue(companyIdValue);
item.setCountryCodes(Arrays.asList("A", "B"));
item.setTitle("Some Title");
JAXBContext jaxbContext = JAXBContext.newInstance(Item.class);
Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
jaxbMarshaller.marshal(item, System.out);
} catch (JAXBException e) {
e.printStackTrace();
}
}
}

JAXB ClassCastException due to root element having the same tag as its child element

I am unmarshalling an XML file taken from the World Bank web service. The root element and children elements have the same tag, as shown below. I am getting a ClassCastException when unmarshalling. This error goes away when I change the root element tag so that it is not the same as its children.
Is JAXB unable to handle this scenario or am I not using JAXB properly?
<data>
<data>
</data>
......
<data>
</data>
</data>
Here is my Java code for reference:
XML with the tag issue: http://api.worldbank.org/countries/all/indicators/SP.POP.TOTL?format=xml
main class
public class CountryPopParse {
public List<CountryPop> parse() throws JAXBException, MalformedURLException, IOException{
JAXBContext jc = JAXBContext.newInstance(CountryPops.class);
Unmarshaller u = jc.createUnmarshaller();
URL url = new URL("http://api.worldbank.org/countries/all/indicators/SP.POP.TOTL?format=xml");
CountryPops countryPops = (CountryPops) u.unmarshal(url);
return countryPops.getCountryPop();
}
public static void main(String[] args) throws JAXBException, IOException, SQLException{
CountryPopParse p = new CountryPopParse();
List<CountryPop> popList= p.parse();
System.out.println(popList.get(0).getDate());
}
}
root element class
#XmlAccessorType(XmlAccessType.FIELD)
#XmlRootElement(name = "data")
public class CountryPops {
#XmlElement(name = "data", type = CountryPop.class)
private List<CountryPop> countryPops = new ArrayList<>();
public CountryPops(){
}
public CountryPops(List<CountryPop> countryPops) {
this.countryPops = countryPops;
}
public List<CountryPop> getCountryPop() {
return countryPops;
}
}
child element class
#XmlAccessorType(XmlAccessType.FIELD)
#XmlRootElement(name = "data")
public class CountryPop {
#XmlElement(name="date")
private int date;
public int getDate() {
return date;
}
}
Just remove the #XmlRootElement(name = "data") from the CountryPop class like the following:
#XmlAccessorType(XmlAccessType.FIELD)
public class CountryPop {
#XmlElement(name="date")
private int date;
public int getDate() {
return date;
}
}
And if you are handling the namespace wb should work fine.

JAXB umarshall exception

I am new to Jaxb and having problem parsing a simple XML. The XML in question is shown below:
<tables>
<table id="1" >
<schema>validator_test</schema>
<name>test1</name>
<rowCountToValidate>6</rowCountToValidate>
<columnTypeCheckRequired>FALSE</columnTypeCheckRequired>
<additionalColumns>column1,column2</additionalColumns>
</table>
<table id="2">
<schema>validator_test</schema>
<name>validate_external1</name>
<rowCountToValidate>2</rowCountToValidate>
<columnTypeCheckRequired>FALSE</columnTypeCheckRequired>
<additionalColumns>column1,column2</additionalColumns>
</table>
<table id="3">
<schema>validator_test</schema>
<name>Test_View1</name>
<rowCountToValidate>2</rowCountToValidate>
<columnTypeCheckRequired>FALSE</columnTypeCheckRequired>
<additionalColumns>column1,column2</additionalColumns>
</table>
</tables>
The Jaxb class to unmarshall this is:-
#XmlRootElement(name = "table")
#XmlType(propOrder = { "name", "schema", "rowCountToValidate","columnTypeCheckRequired","additionalColumns","targetName"})
#Service
public class TableInfo {
private static final boolean TRUE = true;
#Value("${default.row.count.to.validate}")
private Integer defaultRowCountToValidate;
/**
*
*/
public TableInfo() {
}
private String name;
private String schema;
private Integer rowCountToValidate;
private String targetName;
private String columnTypeCheckRequired;
private String additionalColumns;
#XmlElement(name = "name")
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#XmlElement(name = "schema")
public String getSchema() {
return schema;
}
public void setSchema(String schema) {
this.schema = schema;
}
#XmlElement(name = "rowCountToValidate")
public Integer getRowCountToValidate() {
return rowCountToValidate;
}
#XmlElement(name = "columnTypeCheckRequired")
public String getColumnTypeCheckRequired() {
return columnTypeCheckRequired;
}
public void setColumnTypeCheckRequired(String columnTypeCheckRequired) {
this.columnTypeCheckRequired = columnTypeCheckRequired;
}
#XmlElement(name = "additionalColumns")
public String getAdditionalColumns() {
return additionalColumns;
}
public void setAdditionalColumns(String additionalColumns) {
this.additionalColumns = additionalColumns;
}
public void setRowCountToValidate(Integer rowCountToValidate) {
// If user configured value is not null and greater than zero then set
// the value otherwise use default value
if ((null != rowCountToValidate) && (rowCountToValidate.intValue() > 0)) {
this.rowCountToValidate = rowCountToValidate;
}else {
this.rowCountToValidate = defaultRowCountToValidate;
}
}
#XmlElement(name = "targetName")
public String getTargetName() {
return targetName;
}
public void setTargetName(String targetName) {
this.targetName = targetName;
}
#Override
public String toString() {
return ToStringBuilder.reflectionToString(this);
}
}
However, I am ggetting the following exception:-
`JAXB unmarshalling exception; nested exception is javax.xml.bind.UnmarshalException: unexpected element (uri:"", local:"tables"). Expected elements are <{tables}table>`
I would really appreciate if someone can point out the error I am doing. I am new to this and am not really able to understand how jaxb works.
You need to create class Tables with #XmlRootElement(name = "tables") and that class must contain table field with type TableInfo.
When you unmarshal example xml, you need to pass Tables class to unmarshaller.
#XmlRootElement(name = "table")
<tables>
<table id="1" >
Below are the 2 solution for above issue:
You need to generate the classes using XSD.
You need to generate the classes as per your required XML:
in XML table is inside the tables so tables should be the root element.
And table should be in the form of list in tables class.
in your code root element is #XmlRootElement(name = "table") where in your XML file it is "tables"
Suggest you to use xjc command to build java POJO classes automatically
xjc -d -p sample.xsd
-d to define where the generated classes shall be stored in the file system,
-p to define the package to be used

Issue with namespaces in XMLs in JAXB unmarshalling

I have an XML to unmarshall with JAXB. The code works fine if I remove all namespace attributes from the elements but I get a null object after unmarshalling if I keep the namespace attributes.
The XML is like this:
<Animal xmlns="http://allmycats.com/serviceplatform/1.0/" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<Cat z:Id="i3" xmlns:z="http://schemas.microsoft.com/2003/10/Serialization/">
<name>kitty</name>
</Cat>
<Cat z:Id="i2" xmlns:z="http://schemas.microsoft.com/2003/10/Serialization/">
<name>kitty2</name>
</Cat>
</Animal>
My Animal bean is like this:
#XmlRootElement(name = "Animal")
public class Animal{
List<Cat> cats;
#XmlElement(name = "Cat")
public List<Cat> getCats() {
return cats;
}
public void setCats(List<Cat>cats) {
this.cats= cats;
}
}
The Cats bean is like:
#XmlRootElement(name = "Cat")
public class Cat {
private String zId;
#XmlAttribute(name = "z:Id", namespace="http://schemas.microsoft.com/2003/10/Serialization/")
public String getzId() {
return zId;
}
public void setzId(String zId) {
this.zId = zId;
}
private String name;
#XmlElement(name = "name")
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
At runtime, I get an empty object. I tried to remove "z:" from the attribute and I got this exception:
org.xml.sax.SAXParseException; The prefix "z" for attribute "z:Id" associated with an element type "Cat" is not bound.]
If I remove namespaces from cat and Animal, I get this exception:
javax.xml.bind.UnmarshalException: unexpected element (uri:"http://allmycats.com/serviceplatform/1.0/", local:"Animal"). Expected elements are <{}Animal>
Final code to unmarshall is below. The last line gives a null pointer exception
File file = new File(filepath1);
System.out.println("file exists? : "+ file.exists()); // prints true
JAXBContext jaxbContext = JAXBContext.newInstance(Animal2.class);
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
Animal2 animals = (Animal2)jaxbUnmarshaller.unmarshal( file );
System.out.println("--file size: "+animals.getCats().size());
I am not sure how to handle the namespaces and the z: attributes in my POJO classes. Any suggestions please ?
The code works fine if I do not have any namespace or any attribute with namespace in the XML but I cannot alter the XML.
XMLAtribute has atribute namesape, so
#XmlAttribute(name = "Id", namespace="http://schemas.microsoft.com/2003/10/Serialization").
While judging by your xml, the cat is in the same namespace as the animal so
The following code works with JDK 7 (fixed the ns for animal and attribute name for zid).
#XmlRootElement(name = "Animal",namespace = "http://allmycats.com/serviceplatform/1.0/")
public class Animal2{
List<Cat2> cats;
#XmlElement(name = "Cat")
public List<Cat2> getCats() {
return cats;
}
public void setCats(List<Cat2>cats) {
this.cats= cats;
}
}
#XmlRootElement(name = "Cat")
public class Cat2 {
private String zId;
#XmlAttribute(name = "Id", namespace="http://schemas.microsoft.com/2003/10/Serialization/")
public String getzId() {
return zId;
}
public void setzId(String zId) {
this.zId = zId;
}
private String name;
#XmlElement(name = "name")
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}

Getting incorrect values while converting an XML into a Java Object

I m trying to convert XML file into Java Object using Jaxb unmarshalling.
public static void main(String[] args) {
String input = "<project xmlns=\"http://maven.apache.org/POM/4.0.0\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:schemaLocation=\"http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd\">"+
" <key>1</key>" +
"<income>100.335</income>" +
"</project>" ;
NexusClient c1 = new NexusClient();
c1.getObject(input);
}
/*********/
public boolean getObject(String input) {
InputSource inputSource = new InputSource(new StringReader(input));
System.out.println(inputSource);
try {
JAXBContext jaxbContext = JAXBContext
.newInstance(mavenEntity.class);
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
mavenEntity mavenObject = (mavenEntity) jaxbUnmarshaller
.unmarshal(inputSource);
System.out.println("Success"+mavenObject.getIncome());
} catch (JAXBException e) {
System.out.println("Unable to parse the XML Context");
e.printStackTrace();
return false;
}
return true;
}
I m facing an issue while trying to extract "Income" tag information. I couldn't extract correct values using Jaxb. My pojo class is :
#XmlRootElement(name = "project", namespace = "http://maven.apache.org/POM/4.0.0")
#XmlAccessorType(XmlAccessType.FIELD)
public class mavenEntity {
#XmlElement(name = "key", type = String.class)
private String key;
#XmlElement(name = "income", type = String.class)
private String income;
public String getKey() {
return key;
}
public void setKey(String key) {
this.key = key;
}
public String getIncome() {
return income;
}
public void setIncome(String income) {
this.income = income;
}
}
I m getting Null as output for any tag in XML. I guess there is some problem with my name space in XML Annotation. But I really don't understand what it is. Before posting this, I did some groundwork by referring to few links similar to this But still my result is incorrect. Can some one help me out.
The namespace qualification in your model does not match the document. Instead of specifying the namespace on #XmlRootElement and all instances of #XmlElement you can specify the namespace qualification at the package level using #XmlSchema.
package-info.java
#XmlSchema(
namespace = "http://maven.apache.org/POM/4.0.0",
elementFormDefault = XmlNsForm.QUALIFIED)
package org.example.foo;
import javax.xml.bind.annotation.XmlNsForm;
import javax.xml.bind.annotation.XmlSchema;
mavenEntity.java
I have removed the unnecessary annotations from this class (see: http://blog.bdoughan.com/2012/07/jaxb-no-annotations-required.html).
package org.example.foo;
import javax.xml.bind.annotation.XmlSchema;
#XmlRootElement(name = "project")
#XmlAccessorType(XmlAccessType.FIELD)
public class mavenEntity {
private String key;
private String income;
}
For More Information
http://blog.bdoughan.com/2010/08/jaxb-namespaces.html
You will need to add namespace to your #XmlElement annotated fields too
#XmlElement(name = "key", namespace = "http://maven.apache.org/POM/4.0.0")
private String key;
#XmlElement(name = "income", namespace = "http://maven.apache.org/POM/4.0.0")
private String income;
That's because your root element has a particular namespace. Since the nested elements don't have namespace prefix, they are using the root's. I guess this is required by JAXB.
Some alternatives and/or explanations here and here.

Categories