JAXB inheritance + element rename - java

I have the following construction:
#XMLTransient
public abstract class Foo {
protected String name;
}
#XmlRootElement
#XmlType(propOrder={"name"})
public class BarX extends Foo {
public String getXThing() {
return name;
}
public void setXThing(String thing) {
name = thing;
}
}
#XmlRootElement
#XmlType(propOrder={"name"})
public class BarY extends Foo {
public String getYBlah() {
return name;
}
public void setYBlah(String blah) {
name = blah;
}
}
Within the XML I need for BarX instead of name the tag thing and for BarY I would like to have blah instead of name. Is it possible and how I can get this?

You can do the following (you were already pretty close):
Foo
package forum11340316;
import javax.xml.bind.annotation.XmlTransient;
#XmlTransient
public abstract class Foo {
protected String name;
}
BarX
package forum11340316;
import javax.xml.bind.annotation.*;
#XmlRootElement
#XmlType(propOrder={"XThing"})
public class BarX extends Foo {
#XmlElement(name="thing")
public String getXThing() {
return name;
}
public void setXThing(String thing) {
name = thing;
}
}
BarY
package forum11340316;
import javax.xml.bind.annotation.*;
#XmlRootElement
#XmlType(propOrder={"YBlah"})
public class BarY extends Foo {
#XmlElement(name="blah")
public String getYBlah() {
return name;
}
public void setYBlah(String blah) {
name = blah;
}
}
Demo
package forum11340316;
import javax.xml.bind.*;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(BarX.class, BarY.class);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
BarX barX = new BarX();
barX.setXThing("XThing");
marshaller.marshal(barX, System.out);
BarY barY = new BarY();
barY.setYBlah("YBlah");
marshaller.marshal(barY, System.out);
}
}
Output
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<barX>
<thing>XThing</thing>
</barX>
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<barY>
<blah>YBlah</blah>
</barY>
For More Information
http://blog.bdoughan.com/2011/06/ignoring-inheritance-with-xmltransient.html
http://blog.bdoughan.com/2011/06/using-jaxbs-xmlaccessortype-to.html

Related

Mapping XML to Object with same tag names but different attributes

I am trying to convert the below XML string to a Java object using JAXB and eclipse persistence oxm annotations package.
<output>
<rtEvent>
<eventData name="tcppayload">
<data>111111-000000-111111</data>
</eventData>
<eventData name="text">
<data>ABCD</data>
</eventData>
</rtEvent>
</output>
However, the de-serialization does not seem to work. Can someone point out what I might be doing wrong.
Below is the class i'm using to deserialize the string into an object
#XmlRootElement(name = "output")
#XmlAccessorType(XmlAccessType.FIELD)
public class CameraTriggerOutput {
#XmlPath("/rtEvent/eventData[#name=tcppayload]/data/text()")
private String data;
public void toXml() {
try {
JAXBContext ctx = JAXBContext.newInstance(CameraTriggerOutput.class);
Marshaller marshaller = ctx.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
marshaller.marshal(this, System.out);
}
catch (Exception ex) {
ex.printStackTrace();
}
}
}
After running I get the following output
<?xml version="1.0" encoding="UTF-8" standalone="yes"?><output/>
I provide below the code with pure Jaxb, you can try.
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement(name = "eventData")
public class EventData {
private String name;
private String data;
#XmlElement(name = "data")
public String getData() {
return data;
}
public void setData(String data) {
this.data = data;
}
#XmlAttribute(name = "name")
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
import java.util.List;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement(name = "rtEvent")
public class RtEvent {
private List<EventData> edataList;
#XmlElement(name = "eventData")
public List<EventData> getEdataList() {
return edataList;
}
public void setEdataList(List<EventData> edataList) {
this.edataList = edataList;
}
}
import java.util.ArrayList;
import java.util.List;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement(name = "output")
public class Output {
private RtEvent rtEvent;
public RtEvent getRtEvent() {
return rtEvent;
}
public void setRtEvent(RtEvent rtEvent) {
this.rtEvent = rtEvent;
}
public static void main(String[] args) {
try {
EventData eData1 = new EventData();
eData1.setData("111111-000000-111111");
eData1.setName("tcppayload");
EventData eData2 = new EventData();
eData2.setData("ABCD");
eData2.setName("text");
List<EventData> eDataList = new ArrayList<>();
eDataList.add(eData1);
eDataList.add(eData2);
RtEvent rtEvent = new RtEvent();
rtEvent.setEdataList(eDataList);
Output output = new Output();
output.setRtEvent(rtEvent);
JAXBContext ctx = JAXBContext.newInstance(Output.class);
Marshaller marshaller = ctx.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
marshaller.marshal(output, System.out);
} catch (Exception ex) {
ex.printStackTrace();
}
}
}
You Jaxb only as it is part of java, there is no need to include any other annotations. You can make individual classes in your ide and you can test the class Output which has a main method.

Converting XML to Java Object using jaxb (Unmarshal)

I am trying to convert my below xml to java object.
This is my xml:
<ClinicalDocument xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="urn:hl7-org:v3" xmlns:sdtc="urn:hl7-org:sdtc" xmlns:voc="urn:hl7-org:v3/voc">
<confidentialityCode code="" codeSystem=""/>
<languageCode code="en-"/>
<recordTarget>
<patientRole>
<id root="" extension=""/>
<telecom value="" use=""/>
<providerOrganization>
<id root="" extension=""/>
<id root="" extension=""/>
<name>Something</name>
<telecom value=""/>
<addr use="">
<state></state>
<city></city>
<postalCode></postalCode>
<streetAddressLine>2121</streetAddressLine>
</addr>
</providerOrganization>
</patientRole>
</recordTarget>
</ClinicalDocument>
I need to get the value of "name" under "providerOrganization".
Below are my Java classes.
ClinicalDocument.java
package com.biclinical.data;
import java.util.List;
import javax.xml.bind.annotation.*;
#XmlAccessorType(XmlAccessType.FIELD)
#XmlRootElement(name="ClinicalDocument", namespace="urn:hl7-org:v3")
public class ClinicalDocument {
#XmlElement(name="recordTarget")
private List<RecordTarget> recordTarget;
public List<RecordTarget> getRecordTarget() {
return recordTarget;
}
public void setRecordTarget(List<RecordTarget> recordTarget) {
this.recordTarget = recordTarget;
}
#Override
public String toString() {
return "ClinicalDocument [recordTarget=" + recordTarget + "]";
}
}
RecordTarget.java
package com.biclinical.data;
import java.util.List;
import javax.xml.bind.annotation.*;
#XmlAccessorType(XmlAccessType.FIELD)
#XmlRootElement(name="recordTarget")
public class RecordTarget {
#XmlElement(name="patientRole")
private List<PatientRole> patientRole;
public List<PatientRole> getPatientRole() {
return patientRole;
}
public void setPatientRole(List<PatientRole> patientRole) {
this.patientRole = patientRole;
}
#Override
public String toString() {
return "RecordTarget [patientRole=" + patientRole +"]";
}
}
PatientRole.java
package com.biclinical.data;
import java.util.List;
import javax.xml.bind.annotation.*;
#XmlAccessorType(XmlAccessType.FIELD)
#XmlRootElement(name = "patientRole")
public class PatientRole {
/*#XmlElement(name = "id")
private String id;
Double root;
String extension;*/
#XmlElement(name="providerOrganization")
private List<ProviderOrganization> providerOrganization;
public List<ProviderOrganization> getProviderOrganization() {
return providerOrganization;
}
public void setProviderOrganization(List<ProviderOrganization> providerOrganization) {
this.providerOrganization = providerOrganization;
}
}
ProviderOrganisation.java
package com.biclinical.data;
import javax.xml.bind.annotation.*;
#XmlAccessorType(XmlAccessType.FIELD)
#XmlRootElement(name="providerOrganization")
public class ProviderOrganization {
#XmlElement(name="name")
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
#Override
public String toString() {
return "Patient [Name=" + name + "]";
}
}
XMLFileParserSAXUtility.java
public class XMLFileParserSAXUtility extends DefaultHandler {
public static void main(String[] args) {
try {
File file = new File("C:/Users/shivendras/Desktop/Patient19999_Test_Organization1.xml");
JAXBContext jaxbContext = JAXBContext.newInstance(new Class[] {ClinicalDocument.class,RecordTarget.class,PatientRole.class,ProviderOrganization.class});
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
ClinicalDocument clinicalDocument = (ClinicalDocument) jaxbUnmarshaller.unmarshal(file);
//clinicalDocument.getRecordTarget()
String s = ((File) ((PatientRole) ((RecordTarget) clinicalDocument.getRecordTarget()).getPatientRole()).getProviderOrganization()).getName();
System.out.println(s);
} catch (JAXBException e) {
e.printStackTrace();
}
}
I get the result as
Exception in thread "main" java.lang.NullPointerException
at com.biclinical.util.XMLFileParserSAXUtility.main(XMLFileParserSAXUtility.java:27)
And if i try to print syso(clinicalDocument);
Result is ClinicalDocument [recordTarget=null]
Please help me out here!
I think you add the namespace to your #XmlElement :
#XmlElement(name="patientRole")
private List<PatientRole> patientRole;
Should be :
#XmlElement(name="patientRole",namespace="urn:hl7-org:v3")
private List<PatientRole> patientRole;
If you're having any other null in your objects, try adding the namespace.
Also, #XmlRootEntity is only necessary for your root element, in this case your ClinicalDocumentclass, and you only need to give the root class to your JAXBContext :
JAXBContext jaxbContext = JAXBContext.newInstance(ClinicalDocument.class);

JAX-B Nested Lists

I've got an issue with nested lists & was hoping someone could help.I would like to unmarshal the list in the below XML. I was hoping someone could point me in the right direction, I believe me annotations are off. When I try and unmarshall the MyList array it's returned null.
I have an XML:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<root>
<myList>
<name>N1</name>
<type>T1</type>
<version>V1</version>
</myList>
<myList>
<name>N2</name>
<type>T2</type>
<version>V2</version>
</myList>
</root>
MyList object:
#XmlRootElement(name = "myList")
#XmlAccessorType(XmlAccessType.FIELD)
public class MyList {
#XmlValue
private String name;
#XmlValue
private String type;
#XmlValue
private String version;
Root Class:
#XmlAccessorType(XmlAccessType.FIELD)
#XmlRootElement
public class Root {
#XmlElementWrapper(name="myLists")
#XmlElement(name="myList")
private List<MyList> list = new ArrayList<MyList>();
Any help would be much appreciated.
The #XmlValue are wrong. In addition, the #XmlElementWrapper is wrong if the myList elements are not wrapped.
Try this, it works for me.
Root.java
package de.lhorn.so;
import java.util.ArrayList;
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 = "root")
public class Root {
#XmlElement(name = "myList")
private List<MyList> list = new ArrayList<>();
public Root() {
}
public List<MyList> getList() {
return list;
}
public void setList(List<MyList> list) {
this.list = list;
}
#Override
public String toString() {
return "Root{" + "list=" + list + '}';
}
}
MyList.java
package de.lhorn.so;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement(name = "myList")
#XmlAccessorType(XmlAccessType.FIELD)
public class MyList {
private String name;
private String type;
private String version;
public MyList() {
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getVersion() {
return version;
}
public void setVersion(String version) {
this.version = version;
}
#Override
public String toString() {
return "MyList{" + "name=" + name + ", type=" + type + ", version=" + version + '}';
}
}
Main
InputStream is = SOPlayground.class.getResourceAsStream("root.xml");
JAXBContext jaxbContext = JAXBContext.newInstance(Root.class);
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
Root root = (Root) jaxbUnmarshaller.unmarshal(is);
System.out.println(root);
Output
Root{list=[MyList{name=N1, type=T1, version=V1}, MyList{name=N2, type=T2, version=V2}]}
try this, It should work.
#XmlRootElement(name = "root")
#XmlAccessorType (XmlAccessType.FIELD)
public class Root {
#XmlElement(name="myList")
private List<MyList> list = new ArrayList<MyList>();
}
unmarshal
JAXBContext jaxbContext = JAXBContext.newInstance(Root.class);
Unmarshaller jaxbUnmarshaller = jaxbContext.createUnmarshaller();
//We had written this file in marshalling example
Root root= (Root) jaxbUnmarshaller.unmarshal( new File("c:/foo.xml") );
List<MyList> myLists = root.getList();

JAVA/JAXB Help needed

This is gonna be lengthy but I need some enlightenment. I'm new to JAXB so please be lenient with me.
CourseApp:
package Courses;
import java.io.File;
import java.util.ArrayList;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
public class CoursesApp {
public static void main(String[] args) {
Courselist courselist = new Courselist();
courselist.setclassType("Lecture");
courselist.setcourseCode("2002");
courselist.setgroupIndex("1");
courselist.setprofessor("Professor James");
try{
File file = new File("C:\\Courselist.xml");
JAXBContext jaxbContext = JAXBContext.newInstance(Courselist.class);
Marshaller jaxbMarshaller = jaxbContext.createMarshaller();
jaxbMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
jaxbMarshaller.marshal(courselist, file);
jaxbMarshaller.marshal(courselist, System.out);
}catch(JAXBException e)
{
e.printStackTrace();
}
}
}
Courselist:
package Courses;
import java.util.List;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement
public class Courselist {
String courseCode;
String classType;
String groupIndex;
String professor;
public String getcourseCode() {
return courseCode;
}
#XmlElement
public void setcourseCode(String courseCode) {
this.courseCode = courseCode;
}
public String getclassType() {
return classType;
}
#XmlElement
public void setclassType(String classType) {
this.classType = classType;
}
public String getgroupIndex() {
return groupIndex;
}
#XmlElement
public void setgroupIndex(String groupIndex) {
this.groupIndex = groupIndex;
}
public String getprofessor() {
return professor;
}
#XmlElement
public void setprofessor(String professor) {
this.professor = professor;
}
}
Output:
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
- <courselist>
<classType>Lecture</classType>
<courseCode>2002</courseCode>
<groupIndex>1</groupIndex>
<professor>Professor James</professor>
</courselist>
What I want is to create another instance of courselist within the same XML:
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
- <courselist>
-<course>
<classType>Lecture</classType>
<courseCode>2002</courseCode>
<groupIndex>1</groupIndex>
<professor>Professor James</professor>
</course>
-<course>
<classType>Lecture</classType>
<courseCode>2003</courseCode>
<groupIndex>2</groupIndex>
<professor>Professor John</professor>
</course>
</courselist>
I would recommend to have one member in CourseList: List<Course> when Course will include all the members currently in CourseList.
This is the code:
#XmlRootElement
public class Courselist {
#XmlElement List<Course> course = new ArrayList<Course>();
}
Courselist
As oshai answered I would have a model with two classes Courselist and Course. Below is what the Courselist class would look like. To match Java programming conventions the package name is normally lower case. Also it is also often based on a domain name (such as com.example.courses). By default JAXB (JSR-222) implementations look for metadata on the property (get or set methods) so I've put them there (see: http://blog.bdoughan.com/2011/06/using-jaxbs-xmlaccessortype-to.html).
package courses;
import java.util.List;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement
public class Courselist {
List<Course> courses;
#XmlElement(name="course")
public List<Course> getCourses() {
return courses;
}
public void setCourses(List<Course> courses) {
this.courses = courses;
}
}
Course
The information you had in the Courselist class I have moved to a new Course class. JAXB is configuration by exception so you only need to add annotations where you wish the XML representation to differ from the default. In your use case you don't need any annotations on this class (see: http://blog.bdoughan.com/2012/07/jaxb-no-annotations-required.html). I have fixed the casing on your property methods to match the normal Java coding conventions.
package courses;
public class Course {
String courseCode;
String classType;
String groupIndex;
String professor;
public String getCourseCode() {
return courseCode;
}
public void setCourseCode(String courseCode) {
this.courseCode = courseCode;
}
public String getClassType() {
return classType;
}
public void setClassType(String classType) {
this.classType = classType;
}
public String getGroupIndex() {
return groupIndex;
}
public void setGroupIndex(String groupIndex) {
this.groupIndex = groupIndex;
}
public String getProfessor() {
return professor;
}
public void setProfessor(String professor) {
this.professor = professor;
}
}

convert xml to java object using jaxb (unmarshal)

I have the following XML and I need to convert it into a java object.
<tests>
<test-data>
<title>BookTitle</title>
<book>BookName</book>
<count>64018</count>
<test-data>
<title>Book title1</title>
<book>Book Name1</book>
<count>5</count>
</test-data>
<test-data>
<title>Book title2</title>
<book>Book Name3</book>
<count>5</count>
</test-data>
<test-data>
<title>Book title3</title>
<book>Book Name3</book>
<count>4</count>
</test-data>
</test-data>
</tests>
I am not sure what will be my pojo when I use JAXB to convert it.
I created the following POJOs as per my understanding:
public class Tests {
TestData testData;
public TestData getTestData() {
return testData;
}
public void setTestData(TestData testData) {
this.testData = testData;
}
}
public class TestData {
String title;
String book;
String count;
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getBook() {
return book;
}
public void setBook(String book) {
this.book = book;
}
public String getCount() {
return count;
}
public void setCount(String count) {
this.count = count;
}
}
Tests
On the Tests class we will add an #XmlRootElement annotation. Doing this will let your JAXB implementation know that when a document starts with this element that it should instantiate this class. JAXB is configuration by exception, this means you only need to add annotations where your mapping differs from the default. Since the testData property differs from the default mapping we will use the #XmlElement annotation. You may find the following tutorial helpful: http://wiki.eclipse.org/EclipseLink/Examples/MOXy/GettingStarted
package forum11221136;
import javax.xml.bind.annotation.*;
#XmlRootElement
public class Tests {
TestData testData;
#XmlElement(name="test-data")
public TestData getTestData() {
return testData;
}
public void setTestData(TestData testData) {
this.testData = testData;
}
}
TestData
On this class I used the #XmlType annotation to specify the order in which the elements should be ordered in. I added a testData property that appeared to be missing. I also used an #XmlElement annotation for the same reason as in the Tests class.
package forum11221136;
import java.util.List;
import javax.xml.bind.annotation.*;
#XmlType(propOrder={"title", "book", "count", "testData"})
public class TestData {
String title;
String book;
String count;
List<TestData> testData;
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getBook() {
return book;
}
public void setBook(String book) {
this.book = book;
}
public String getCount() {
return count;
}
public void setCount(String count) {
this.count = count;
}
#XmlElement(name="test-data")
public List<TestData> getTestData() {
return testData;
}
public void setTestData(List<TestData> testData) {
this.testData = testData;
}
}
Demo
Below is an example of how to use the JAXB APIs to read (unmarshal) the XML and populate your domain model and then write (marshal) the result back to XML.
package forum11221136;
import java.io.File;
import javax.xml.bind.*;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(Tests.class);
Unmarshaller unmarshaller = jc.createUnmarshaller();
File xml = new File("src/forum11221136/input.xml");
Tests tests = (Tests) unmarshaller.unmarshal(xml);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(tests, System.out);
}
}

Categories