Issue with namespaces in XMLs in JAXB unmarshalling - java

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;
}
}

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();
}
}
}

Unmarshalling xml to modal class failed using JAXB in 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.

Attribute to a JAXB Element

I'm using JAXB for creating xml. I want to set attribute 'lang' on elements PrimaryValue and AlternativeSpelling.
<AgencyOrUnit>
<PrimaryValue lang="el">ΓΑΔΑ</PrimaryValue>
<AlternativeSpelling lang="en">Athens General Police Directorate</AlternativeSpelling>
</AgencyOrUnit>
Here's my code:
#XmlRootElement(name = "OwnerReference")
#XmlType(propOrder = { "primaryValue", "alternativeSpelling"})
public class AgencyOrUnit {
private String PrimaryValue;
private String AlternativeSpelling;
public String getPrimaryValue() {
return PrimaryValue;
}
public void setPrimaryValue(String PrimaryValue){
this.PrimaryValue = PrimaryValue;
}
public String getAlternativeSpelling() {
return AlternativeSpelling;
}
public void setAlternativeSpelling(String AlternativeSpelling){
this.AlternativeSpelling = AlternativeSpelling;
}
}
Here's process of marshalling:
AgencyOrUnit agencyOrUnit = new AgencyOrUnit();
agencyOrUnit.setPrimaryValue("ΓΑΔΑ");
agencyOrUnit.setAlternativeSpelling("General Police");
The problem is that I don't know how to set property with value on elements primaryValue and alternativeSpelling?
You can use annotations #XmlValue & #XmlAttribute but you need to create a new class to hold both lang and the original value string. Something like this:
#Setter
#AllArgsConstructor
public class LocaleString {
private String lang;
private String value;
#XmlAttribute
public String getLang() {
return lang;
}
#XmlValue
public String getValue() {
return value;
}
}
Then modify your AgencyOrUnit accordingly:
#XmlRootElement(name = "OwnerReference")
#XmlType(propOrder = { "primaryValue", "alternativeSpelling"})
#Getter #Setter
public class AgencyOrUnit {
private LocaleString PrimaryValue;
private LocaleString AlternativeSpelling;
}
Test it:
#Test
void test() throws JAXBException {
AgencyOrUnit agencyOrUnit = new AgencyOrUnit();
agencyOrUnit.setPrimaryValue(new LocaleString("el", "ΓΑΔΑ"));
agencyOrUnit.setAlternativeSpelling(new LocaleString("en", "General Police"));
JAXBContext ctx = JAXBContext.newInstance(AgencyOrUnit.class);
Marshaller marshaller = ctx.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
marshaller.marshal(agencyOrUnit, System.out);
}
and you should see this:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<OwnerReference>
<primaryValue lang="el">ΓΑΔΑ</primaryValue>
<alternativeSpelling lang="en">General Police</alternativeSpelling>
</OwnerReference>

Unmarshaling XML

I'm trying to unmarshal existing xml file so that i can handle the data properly but the XML structure looks weird. below is the sample of the xml together with the objects I've created.
<?xml version="1.0" encoding="UTF-8"?>
<Record>
<identifier>11</identifier>
<TotalRecords>266</TotalRecords>
<ListOfSections>
<SECTION>AA1001</SECTION>
<ListOfStudents>
<SequenceNumber>11</SequenceNumber>
<RecordCount>1</RecordCount>
<StudentId>201614354</StudentId>
</ListOfStudents>
<SECTION>AA1002</SECTION>
<ListOfStudents>
<SequenceNumber>15</SequenceNumber>
<RecordCount>1</RecordCount>
<StudentId>201614356</StudentId>
<SequenceNumber>16</SequenceNumber>
<RecordCount>2</RecordCount>
<StudentId>201614355</StudentId>
</ListOfStudents>
</ListOfSections>
</Record>
Below are my java classes. I just removed the variables for readability.
#XmlRootElement
public class Record {
#XmlElement(name = "TotalRecords")
public Integer getTotalNoOfRecords() {
return totalNoOfRecords;
}
#XmlElement(name = "ListOfSections")
public List<Section> getSectionList() {
return sectionList;
}
}
#XmlRootElement
public class Section {
#XmlElement(name = "SECTION")
public String getSection() {
return section;
}
#XmlElement(name = "ListOfStudents")
public List<Student> getStudentList() {
return studentList;
}
}
#XmlRootElement
public class Student {
#XmlElement(name = "SequenceNumber")
public Integer getSequenceNumber() {
return sequenceNumber;
}
#XmlElement(name = "RecordCount")
public Integer getRecordCount() {
return recordCount;
}
#XmlElement(name = "StudentId")
public Integer getStudentId() {
return studentId;
}
}
I was trying to get all the records within the ListOfSections tag but I'm only getting the last section which is AA1002.
for the ListOfStudents I'm only getting the first record in my case I'm only getting record with sequence number 15
<SequenceNumber>12</SequenceNumber>
<RecordCount>2</RecordCount>
<StudentId>201614355</StudentId>
This simplified code works with your xml, it should give you a hint where to look for the problem:
class Record {
#XmlElementWrapper(name="ListOfSections")
#XmlElement(name="SECTION")
List<String> listOfSections;
}
here how to run:
Record r = JAXB.unmarshal(new File("1.xml"), Record.class);
System.out.println(r.listOfSections);
result:
[AA1001, AA1002]

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

Categories