JAXB Generate xmlns:xsi declaration in a nested node - java

I am looking to control where JAXB generates the xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" declaration when marshalling to XML. I've seen solutions like this to add it to the root element using the JAXB_SCHEMA_LOCATION property, however I don't want it on the root node, I want it somewhere in between. Here's what I've got:
#XmlRootElement(name = "RootNode")
#XmlAccessorType(XmlAccessType.NONE)
public class RootNode {
#XmlElement(name = "IntermediateNode")
private IntermediateNode intermediateNode;
//getter & setter
}
#XmlAccessorType(XmlAccessType.NONE)
public class IntermediateNode {
#XmlElement(name = "MyEntity")
private MyEntity myEntity;
//getter and setter
}
#XmlAccessorType(XmlAccessType.NONE)
public class MyEntity {
#XmlElement(name = "Name")
private String name;
#XmlElement(name = "Title", nillable = true)
private String title;
//getters and setters
}
Serialize like:
MyEntity myEntity = new MyEntity();
myEntity.setName("George");
myEntity.setTitle(null);
IntermediateNode intNode = new IntermediateNode();
intNode.setMyEntity(myEntity);
RootNode rootNode = new RootNode();
rootNode.setIntermediateNode(intNode);
JAXBContext context = JAXBContext.newInstance(RootNode.class);
Marshaller marshaller = context.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(rootNode, System.out);
Produces XML like:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<RootNode>
<IntermediateNode>
<MyEntity>
<Name>George</Name>
<Title xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/>
</MyEntity>
</IntermediateNode>
</RootNode>
But what I want is:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<RootNode>
<IntermediateNode xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<MyEntity>
<Name>George</Name>
<Title xsi:nil="true"/>
</MyEntity>
</IntermediateNode>
</RootNode>
I even tried moving my IntermediateNode and MyEntity classes into their own package with a package-info.java like this, but that just rolled the xmlns:xsi up to the root element.
#javax.xml.bind.annotation.XmlSchema(
xmlns = {
#javax.xml.bind.annotation.XmlNs(prefix = "xsi", namespaceURI = "http://www.w3.org/2001/XMLSchema-instance")
},
elementFormDefault = javax.xml.bind.annotation.XmlNsForm.QUALIFIED)
package com.example.intermediate;
Is it possible to get what I want?

Related

Multiple namespaces with JAXB

I am working on a XML file with multiple naespaces and I am trying ot unmarshal it.
I have looked into some questions on stack overflow previously but have not yet met with the solution.
The XML file:
<?xml version="1.0" encoding="UTF-8"?>
<Registry xmlns="http://www.registar.com" xmlns:ms="http://www.registar.com/ScoreVariant">
<Student>
<FirstName>RP</FirstName>
<Value>
<ms:String>Pass</ms:String>
</Value>
</Student>
<Student>
<FirstName>SK</FirstName>
<Value>
<ms:Int>100</ms:Int>
</Value>
</Student>
</Registry>
The Registry, Student class
#Data
#XmlRootElement(name="Registry")
#XmlAccessorType(XmlAccessType.FIELD)
public class Registry {
#XmlElement
private List<Student> Student;
}
Student:
#Data
#XmlAccessorType(XmlAccessType.FIELD)
//#XmlType(namespace = "http://www.registar.com/Grad")
public class Student {
#XmlElement
private String FirstName;
private Value value; // suggestions to achieve this with different namespaces
}
I have a package-info.java file
#XmlSchema(
namespace="http://www.registar.com",
elementFormDefault=XmlNsForm.QUALIFIED,
xmlns={
#XmlNs(prefix = "", namespaceURI = "http://www.registar.com"),
#XmlNs(prefix = "ms",namespaceURI = "http://www.registar.com/Grad")
}
)
#XmlAccessorType(XmlAccessType.FIELD)
import javax.xml.bind.annotation.*;
And i try to print out the unmarshalled entries. However the different namespaces are not recognised.
The output shows an error..
unexpected element (URI: "http://www.registar.com", local: "Registry"). Expected elements are <{} Registry>
at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallingContext.handleEvent(UnmarshallingContext.java:744)
at com.sun.xml.bind.v2.runtime.unmarshaller.Loader.reportError(Loader.java:262)
at com.sun.xml.bind.v2.runtime.unmarshaller.Loader.reportError(Loader.java:257)
at com.sun.xml.bind.v2.runtime.unmarshaller.Loader.reportUnexpectedChildElement(Loader.java:124)
at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallingContext$DefaultRootLoader.childElement(UnmarshallingContext.java:1149)
at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallingContext._startElement(UnmarshallingContext.java:574)
at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallingContext.startElement(UnmarshallingContext.java:556)
at com.sun.xml.bind.v2.runtime.unmarshaller.SAXConnector.startElement(SAXConnector.java:168)
at java.xml/com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.startElement(AbstractSAXParser.java:518)
at java.xml/com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.scanStartElement(XMLNSDocumentScannerImpl.java:374)
at java.xml/com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl$NSContentDriver.scanRootElementHook(XMLNSDocumentScannerImpl.java:613)
at java.xml/com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl$FragmentContentDriver.next(XMLDocumentFragmentScannerImpl.java:3078)
at java.xml/com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl$PrologDriver.next(XMLDocumentScannerImpl.java:836)
at java.xml/com.sun.org.apache.xerces.internal.impl.XMLDocumentScannerImpl.next(XMLDocumentScannerImpl.java:605)
at java.xml/com.sun.org.apache.xerces.internal.impl.XMLNSDocumentScannerImpl.next(XMLNSDocumentScannerImpl.java:112)
at java.xml/com.sun.org.apache.xerces.internal.impl.XMLDocumentFragmentScannerImpl.scanDocument(XMLDocumentFragmentScannerImpl.java:541)
at java.xml/com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:888)
at java.xml/com.sun.org.apache.xerces.internal.parsers.XML11Configuration.parse(XML11Configuration.java:824)
at java.xml/com.sun.org.apache.xerces.internal.parsers.XMLParser.parse(XMLParser.java:141)
at java.xml/com.sun.org.apache.xerces.internal.parsers.AbstractSAXParser.parse(AbstractSAXParser.java:1224)
at java.xml/com.sun.org.apache.xerces.internal.jaxp.SAXParserImpl$JAXPSAXParser.parse(SAXParserImpl.java:635)
at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal0(UnmarshallerImpl.java:258)
at com.sun.xml.bind.v2.runtime.unmarshaller.UnmarshallerImpl.unmarshal(UnmarshallerImpl.java:229)
at javax.xml.bind.helpers.AbstractUnmarshallerImpl.unmarshal(AbstractUnmarshallerImpl.java:170)
at javax.xml.bind.helpers.AbstractUnmarshallerImpl.unmarshal(AbstractUnmarshallerImpl.java:209)
at javax.xml.bind.helpers.AbstractUnmarshallerImpl.unmarshal(AbstractUnmarshallerImpl.java:194)
at Mainparser.main(Mainparser.java:20)
Could you please suggest or provide some guidance here?
Update: As per the suggestion, I passed the prefix of ns0 to the default namespace and made the changes. I do not get any error, but the output is not as expected
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Registry>
<Student>
<FirstName>RP</FirstName>
<Value/>
</Student>
<Student>
<FirstName>SK</FirstName>
<Value/>
</Student>
</Registry>
UPDATE2:
The xmlns:ms has the different scorevariants( it could be string or int or double).. I am not able to extract this information as well.. There needs to be a Value class, but I do not seem to find a way to extract the information
Update 3:
The value class was written as per the suggestion.
#Data
#XmlAccessorType(XmlAccessType.FIELD)
public class Value {
#XmlElements( value = {
#XmlElement(name="ms:String",type = String.class),
#XmlElement(name="ms:Int",type = Integer.class)
})
private Object value;
}
The output is as below:
<Registry xmlns:ms="http://www.registar.com/ScoreVariant" xmlns="http://www.registar.com">
<Student>
<FirstName>RP</FirstName>
<Value/>
</Student>
<Student>
<FirstName>SK</FirstName>
<Value/>
</Student>
</Registry>
Rest of the code is the same.. Please suggest if there is any dependency that I am missing on..
You would be able to achieve this by doing the following:
Your package-info.java
#XmlSchema(
namespace = "http://www.registar.com",
elementFormDefault = XmlNsForm.QUALIFIED,
xmlns = {
#XmlNs(prefix = "", namespaceURI = "http://www.registar.com"),
#XmlNs(prefix = "", namespaceURI = "http://www.registar.com/Grad"),
#XmlNs(prefix = "ms", namespaceURI = "http://www.registar.com/Value")
}
)
#XmlAccessorType(XmlAccessType.FIELD)
Your Value class, which you did not provide here, so I made an assumption of how it would look like:
#XmlRootElement(name = "Value", namespace = "http://www.registar.com/Value")
#XmlAccessorType(XmlAccessType.FIELD)
public class Value {
#XmlElement(name = "String", namespace = "http://www.registar.com/Value")
private String string;
#XmlElement(name = "Int", namespace = "http://www.registar.com/Value")
private Integer number;
}
Once you do the Marshalling your XML will look like this:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Registry xmlns="http://www.registar.com" xmlns:ms="http://www.registar.com/Value"
xmlns:ns3="http://www.registar.com/Grad">
<Student>
<FirstName>RP</FirstName>
<Value>
<ms:String>Pass</ms:String>
</Value>
</Student>
<Student>
<FirstName>SK</FirstName>
<Value>
<ms:Int>100</ms:Int>
</Value>
</Student>
</Registry>
Here the namespace is registered and configured to have a prefix, subsequently we tell the fields in the Value class which namespace they're using.
My experience of the actual specs of SOAP are not sufficient to tell you whether this would be a valid SOAP. My testing however allowed for both marshalling and unmarshalling if this XML file.
I believe this is something you are looking for:
XML:
<?xml version="1.0" encoding="UTF-8"?>
<Registry xmlns="http://www.registar.com" xmlns:ms="http://www.registar.com/ScoreVariant">
<Student>
<FirstName>RP</FirstName>
<Value>
<ms:String>Pass</ms:String>
</Value>
</Student>
<Student>
<FirstName>SK</FirstName>
<Value>
<ms:Int>100</ms:Int>
</Value>
</Student>
</Registry>
Registry:
#XmlRootElement(name = "Registry")
#Data
#XmlAccessorType(XmlAccessType.FIELD)
public class Registry {
#XmlElement(name = "Student")
List<Student> Student;
}
Student:
#Data
#XmlAccessorType(XmlAccessType.FIELD)
public class Student {
#XmlElement(name="FirstName")
private String FirstName;
private Value Value;
}
Value:
#Data
#XmlAccessorType(XmlAccessType.FIELD)
public class Value {
#XmlElements({
#XmlElement(name = "ms:String", type = String.class),
#XmlElement(name = "ms:Int", type = Integer.class)
})
private Object value;
}
package-info.java:
#XmlSchema(
elementFormDefault = XmlNsForm.QUALIFIED,
namespace = "http://www.registar.com",
xmlns = {#XmlNs(prefix = "", namespaceURI = "http://www.registar.com"),
#XmlNs(prefix = "ms", namespaceURI = "http://www.registar.com/ScoreVariant")})
package stackover;
import jakarta.xml.bind.annotation.XmlNs;
import jakarta.xml.bind.annotation.XmlNsForm;
import jakarta.xml.bind.annotation.XmlSchema;
Main:
public class Main {
public static void main(String[] args) throws JAXBException, XMLStreamException {
final InputStream inputStream = Main.class.getClassLoader().getResourceAsStream("sample.xml");
final XMLStreamReader xmlStreamReader = XMLInputFactory.newInstance().createXMLStreamReader(inputStream);
final Unmarshaller unmarshaller = JAXBContext.newInstance(Registry.class).createUnmarshaller();
final Registry registry = unmarshaller.unmarshal(xmlStreamReader, Registry.class).getValue();
System.out.println(registry.toString());
Marshaller marshaller = JAXBContext.newInstance(Registry.class).createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FRAGMENT, Boolean.TRUE);
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
marshaller.marshal(registry, System.out);
}
}
package-info.java
#XmlSchema(
namespace="http://www.registar.com",
xmlns={
#XmlNs(prefix = "",namespaceURI = "http://www.registar.com"),
#XmlNs(prefix = "ms",namespaceURI = "http://www.registar.com/ScoreVariant")
},
elementFormDefault=XmlNsForm.QUALIFIED
)package code;
//#XmlAccessorType(XmlAccessType.FIELD)
import javax.xml.bind.annotation.XmlNs;
import javax.xml.bind.annotation.XmlNsForm;
import javax.xml.bind.annotation.XmlSchema;
Registry(Student=[Student(FirstName=RP, Value=Value(value=Pass)), Student(FirstName=SK, Value=Value(value=100))])
<Registry xmlns="http://www.registar.com" xmlns:ms="http://www.registar.com/ScoreVariant">
<Student>
<FirstName>RP</FirstName>
<Value>
<ms:String>Pass</ms:String>
</Value>
</Student>
<Student>
<FirstName>SK</FirstName>
<Value>
<ms:Int>100</ms:Int>
</Value>
</Student>
</Registry>

unmarshal using jaxb having inner tag

I want to unmarshal my below xml file using JAXB.
<School>
<Student>
<Name> My xyz<Name>
<Hobbies> Playing Cricket <sup>+</sup> Watching TV</Hobbies>
</Student>
</School>
In Above example , There is one school with student which having hobbies.
Whenever i unmarshal above xml using (#XmlPath) i got only "Watching TV" but not "Playing Cricket".
I have tried to unmarshal using "DomHandler" also but not success.
Thanks.
I think your XML should be something like this:
<?xml version="1.0" encoding="UTF-8"?>
<School>
<Student>
<Name>My xyz</Name>
<Hobbies>
<Name>Playing Cricket</Name>
<Hobby>
</Hobby>
<Name>Playing Cricket</Name>
</Hobbies>
</Student>
<!-- OTHER STUDENTS FOLLOW-->
</School>
and then the correspondant java object structure would be something like:
#XmlAccessorType(XmlAccessType.FIELD)
#XmlRootElement(name = "School")
class School {
#XmlElement(required = true, name = "Student")
Student student;
}
#XmlAccessorType(XmlAccessType.FIELD)
class Hobby {
#XmlElement(required = true, name = "Name")
String name;
}
#XmlAccessorType(XmlAccessType.FIELD)
class Student {
#XmlElement(required = true, name = "Name")
String name;
#XmlElement(required = true, name = "Hobbies")
List<Hobby> hobbies;
}
I took off the getters and the setters for brevity.

jaxb reference xmlID between xml files

I tried the approach in this post
However I am getting a
>
1 counts of IllegalAnnotationExceptions
XmlIDREF property is referencing a type "java.lang.String" that doesn't have an XmlID property.
this problem is related to the following location:
at private externalReferences.Department
externalReferences.Employee.department
at externalReferences.Employee
at private java.util.List externalReferences.Company.employees
at externalReferences.Company
The two xml Files are the following:
employee.xml
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<company>
<employeeList>
<employee name="Jane Doe" id="1">
<department>1</department>
</employee>
<employee name="John Smith" id="2">
<department>2</department>
</employee>
<employee name="Anne Jones" id="3">
<department>3</department>
</employee>
</employeeList>
</company>
department.xml
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<departmentList>
<departmentList>
<department name="Dev" id="1"/>
<department name="Sales" id="2"/>
<department name="Research" id="3"/>
</departmentList>
</departmentList>
The employee.xml references the department and I want to point to the right department objects when unmarshalling employee.xml.
Classes are as follows:
Company.java
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class Company {
#XmlElementWrapper(name = "employeeList")
#XmlElement(name="employee")
private List<Employee> employees;
#XmlElementWrapper(name = "departmentList")
#XmlElement(name="department")
private List<Department> departments;
public Company() {
employees = new ArrayList<Employee>();
departments = new ArrayList<Department>();
}
...
}
Employee.java
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class Employee {
#XmlAttribute
#XmlID
private String id;
public String getId() {
return id;
}
#XmlIDREF
private Employee manager;
#XmlJavaTypeAdapter(EmpAdapter.class)
#XmlIDREF
private Department department;
}
Department.java
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class Department {
#XmlAttribute
#XmlID
private String id;
...
}
DepartmentList.java
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class DepartmentList {
#XmlElementWrapper(name = "departmentList")
#XmlElement(name="department")
private List<Department> departments;
Then I run the following in Main
JAXBContext jc = JAXBContext.newInstance(DepartmentList.class); Unmarshaller unmarshaller = jc.createUnmarshaller();
DepartmentList depList = (DepartmentList) unmarshaller.unmarshal(new FileReader(DepRef));
EmpAdapter adapter = new EmpAdapter();
for(Department dep : depList.getDepartments()) {
adapter.getDepList().put(dep.getId(), dep);
}
JAXBContext jc2 = JAXBContext.newInstance(Company.class);
Unmarshaller unmarshaller2 = jc2.createUnmarshaller();
unmarshaller2.setAdapter(adapter);
Company company2 = (Company) unmarshaller2.unmarshal(new FileReader(empRef));
I feel that having one XMLIDREF refer to employee id and the other XMLIDREF refer to department id is part of the problem. But that is required since the manager field references other employee objects.
Can someone please help me with this. Thank you
The problem arises from class Company that corresponds to an XML document containing employees and departments. However, you've got two separate documents. Apparently you want one final class containing both lists.
(1) You could define a class EmployeeList for employees only, similar to the one for departments (DepartmentList). This will still let you write an application class Company into which you set the references for both lists.
(2) Change the annotation for Company.departments
#XmlTransient
private List<Department> departments;
marshal like you do now, and set the List with the reference you have from unmarshalling the corresponding XML into the returned object.

JAXB Marshaller does not have elements whos value is null

When I marshall a java object using JAXB Marshaller, the marshaller does not create empty elements for null files in the java object. For example, I have a following java object:
public class PersonTraining {
#XmlElement(name = "Val1", required = true)
protected BigDecimal val1;
#XmlElement(name = "Val2", required = true, nillable = true)
protected BigDecimal val2;
#XmlElement(name = "Val3", required = true, nillable = true)
#XmlSchemaType(name = "dateTime")
protected XMLGregorianCalendar val3;
}
When I take an instance of this object, and marshall into an XML, I get the following (This is beacuse I did not set the value for Val2):
<PersonTraining>
<Val1>1</Val1>
<Val3>2010-01-01T00:00:00.0-05:00</Val3>
</PersonTraining>
However, I had expected hte following result from the marshalling operation (Infact, I specifically need element as well so that the XML can be validated against the XSD)
<PersonTraining>
<Val1>1</Val1>
<Val2></Val2>
<Val3>2010-01-01T00:00:00.0-05:00</Val3>
</PersonTraining>
Please let me know what option I would need to set so that the null value in the object attributes can ALSO be marshalled, and returned as empty/null elements.
Here is the marshalling code:
StringWriter sw = new StringWriter();
JAXBContext jc = JAXBContext.newInstance("person_training");
Marshaller m = jc.createMarshaller();
m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
m.marshal(ptl, sw);
By default a JAXB (JSR-222) implementation will not marshal an attribute/element for null values. This will be true for the following field in your Java model.
#XmlElement(name = "Val1", required = true)
protected BigDecimal val1;
You can override this behaviour by specifying nillable=true on the #XmlElement annotation like you have done here:
#XmlElement(name = "Val2", required = true, nillable = true)
protected BigDecimal val2;
This will cause the xsi:nil="true" attribute to be leverage:
<Val2 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/>
For more information:
http://blog.bdoughan.com/2012/04/binding-to-json-xml-handling-null.html
Java Model
PersonTraining
Since you are annotating the fields you should make sure you specify #XmlAccessorType(XmlAccessType.FIELD) at the class or package level (see: http://blog.bdoughan.com/2011/06/using-jaxbs-xmlaccessortype-to.html).
import java.math.BigDecimal;
import javax.xml.bind.annotation.*;
import javax.xml.datatype.XMLGregorianCalendar;
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class PersonTraining {
#XmlElement(name = "Val1", required = true)
protected BigDecimal val1;
#XmlElement(name = "Val2", required = true, nillable = true)
protected BigDecimal val2;
#XmlElement(name = "Val3", required = true, nillable = true)
#XmlSchemaType(name = "dateTime")
protected XMLGregorianCalendar val3;
}
Demo Code
Demo
import javax.xml.bind.*;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(PersonTraining.class);
PersonTraining pt = new PersonTraining();
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(pt, System.out);
}
}
Output
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<personTraining>
<Val2 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/>
<Val3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true"/>
</personTraining>

JAXB unmarshalling with java generics

I am trying to unmarshall an XML document from a legacy system using JAXB. I have an xml structure as follows :
<response>
<id>000000</id>
<results>
<result>
<!-- Request specific xml content -->
<year>2003</year>
<title>Lorem Ipsum</title>
<items>
<item>I1</item>
<item>I2</item>
</items>
</result>
<result>
<year>2007</year>
<title>Dolor sit amet</title>
<items>
<item>K1</item>
<item>K2</item>
</items>
</result>
</results>
</response>
The tags inside the part specified by <result> tag will change depending on my request. Since the content may change I decided to use generics for result items and I have prepared my java beans with annotations as following:
// imports here
#XmlRootElement(name="response")
#XmlAccessorType(XmlAccessType.FIELD)
public class XResponse<T>{
private String id;
#XmlElementWrapper(name="results")
#XmlElement(name="result")
private List<T> results;
// setters and getters
}
...
#XmlRootElement(name="result")
#XmlAccessorType(XmlAccessType.FIELD)
public class X1Result{
private String year;
private String title;
#XmlElementWrapper(name="items")
#XmlElement(name="item")
private List<String> items;
// setters and getters
}
...
I tried unmarshalling the xml document via the code below:
JAXBContext context = JAXBContext.newInstance(XResponse.class, X1Result.class);
Unmarshaller um = context.createUnmarshaller();
XResponse<X1Result> response = (XResponse<X1Result>) um.unmarshal( xmlContent );
List<X1Result> results = unmarshal.getResults();
for (X1Result object : results) {
System.out.println(object.getClass());
}
I have a problem during the unmarshalling that it can't cast the list items into X1Result class. Instead it uses org.apache.xerces.dom.ElementNSImpl.
What should I do to make JAXB Unmarshaller use X1Result class?
Thanks in advance
I think you should use inheritance instead of generics. Given an XML like this:
<?xml version="1.0" encoding="UTF-8"?>
<response xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<id>000000</id>
<results>
<result xsi:type="X1Result">
<year>2003</year>
<title>Lorem Ipsum</title>
<items>
<item>I1</item>
<item>I2</item>
</items>
</result>
<result xsi:type="X1Result">
<year>2007</year>
<title>Dolor sit amet</title>
<items>
<item>K1</item>
<item>K2</item>
</items>
</result>
</results>
</response>
You can dynamically bind your <result> entries. You have a top-level type:
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "XResult")
#XmlSeeAlso({
X1Result.class
})public abstract class XResult {
}
And you have implementing classes:
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "X1Result")
public class X1Result extends XResult {
#XmlElement(name = "year")
private String year;
#XmlElement(name = "title")
private String title;
#XmlElementWrapper(name = "items")
#XmlElement(name = "item")
private List<String> items;
...
}
Use the top-level type in your XResponse class:
#XmlRootElement(name = "response")
#XmlAccessorType(XmlAccessType.FIELD)
public class XResponse {
#XmlElement(name = "id")
private String id;
#XmlElementWrapper(name = "results")
#XmlElement(name = "result")
private List<XResult> results;
...
}
And you can unmarshall using the top-level type:
context = JAXBContext.newInstance(XResponse.class, XResult.class);
Unmarshaller unmarshaller = context.createUnmarshaller();
XResponse response = (XResponse) unmarshaller.unmarshal(new File("testfile.xml"));
List<XResult> results = response.getResults();
for (XResult object : results) {
System.out.println(object.getClass());
}

Categories

Resources