XML:JAXB Mapping Java Objects and XML Document - java

I'm trying to implement all Java classes for handling the following XML code snippet:
<party date="2012-09-30">
<guest name="Albert">
<drink>wine</drink>
</guest>
</party>
I've wrote 3 classes:
Party.java:
package li.mnet.www.java.xml;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlRootElement;
#XmlAccessorType(XmlAccessType.FIELD)
#XmlRootElement(name = "party")
public class Party {
#XmlAttribute(name = "date")
private String partyDate;
public Party() {}
public String getPartyDate() {return partyDate;}
public void setPartyDate(String partyDate) {
this.partyDate = partyDate;
}
}
Guest.java:
package li.mnet.www.java.xml;
import javax.xml.bind.annotation.XmlElement;
public class Guests {
private String name;
public Guests() {}
public void setGuestName(String name) {this.name = name;}
#XmlElement(name = "name")
public String getGuestName() {return name;}
}
PartyRunner.java:
package li.mnet.www.java.xml;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
public class PartyRunner {
public static void main(String[] args) {
Party party = new Party();
Guests guest = new Guests();
party.setPartyDate("2012-09-03");
guest.setGuestName("Albert");
JAXBContext context;
try {
context = JAXBContext.newInstance(Party.class);
Marshaller m = context.createMarshaller();
m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
m.marshal(party, System.out);
} catch (JAXBException e) {e.printStackTrace();}
}
}
After running the application i get following console output:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<party date="2012-09-03"/>
What do i have to change, that class Guest.java gets printed out too?
Thanks a lot for your support!

When you're trying to marshal some data through JAXB, you'll give it an instance of your class (here is Party) and it will traverse your object and all of its attributes and tries to serialize them to the final output using hints provided by JAXB annotations.
Remember that JAXB ignores properties of the class which has no JAXB annotation. Also You can it tell whether to generate an XML Element or XML Attribute for given class property. You can use these annotations on properties or their getter methods.
In your example, you want to have a guest element inside party element. In your main method (in PartyRunner), you're marshaling an instance of Party class, but this class has no reference to your Guests class. Creating an instance of Guests class wouldn't be enough. You have to create a logical relationship between two classes and annotate them to make it possible to generate an appropriate XML. So your Party class should be something like this:
import javax.xml.bind.annotation.*;
#XmlAccessorType(XmlAccessType.FIELD)
#XmlRootElement(name = "party")
public class Party {
#XmlAttribute(name = "date")
private String partyDate;
#XmlElement(name="guest")
private Guests guests;
public Party() {}
public String getPartyDate() {return partyDate;}
public void setPartyDate(String partyDate) {
this.partyDate = partyDate;
}
public Guests getGuests() {
return guests;
}
public void setGuests(Guests guests) {
this.guests = guests;
}
}
If you run the PartyRunner again you'll have something like this in your output:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<party>
<partyDate>2012-09-03</partyDate>
<guest>
<name>Albert</name>
</guest>
</party>
As you can see, there is an inner element named name in your guests element. This is due to the annotation you've specified for getGuestName method in your Guests class. In order to make JAXB to generate an XML attribute for this property (instead of an XML element), you need to change the JAXB annotation in your Guests class too. You have annotated the getGuestName method as #XmlElement. This will cause to generate an XML element. If you change it to #XmlAttribute and run the PartyRunner again, you'll have this in your output:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<party date="2012-09-03">
<guest name="Albert"/>
</party>
Also in your sample XML you have a drink element inside your guests property. Same is true for drink property. The drink could be a String property in your Guests class annotated as #XmlAttribute(name = "drink"). So your final Guests class to generate the XML mentioned at the beginning of your question should be something like this:
import javax.xml.bind.annotation.XmlAttribute;
import javax.xml.bind.annotation.XmlElement;
public class Guests {
private String name;
private String drinkType;
public Guests(){}
public void setGuestName(String name) {this.name = name;}
#XmlAttribute(name = "name")
public String getGuestName() {return name;}
#XmlElement(name = "drink")
public String getDrinkType() {
return drinkType;
}
public void setDrinkType(String drinkType) {
this.drinkType = drinkType;
}
}
and your PartyRunner should initialize the drink property to something like wine:
public static void main(String[] args) {
Party party = new Party();
Guests guest = new Guests();
party.setPartyDate("2012-09-03");
guest.setGuestName("Albert");
guest.setDrinkType("wine");
party.setGuests(guest);
JAXBContext context;
try {
context = JAXBContext.newInstance(Party.class);
Marshaller m = context.createMarshaller();
m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
m.marshal(party, System.out);
} catch (JAXBException e) {e.printStackTrace();}
}

I think the party class should contain a guest (or list of guests if you want more)
public class Party {
#XmlAttribute(name = "date")
private String partyDate;
private Guest guest;
public Party() {}
public String getPartyDate() {return partyDate;}
public void setPartyDate(String partyDate) {
this.partyDate = partyDate;
}
// getter and setter for guest
}
set the guest of the party object then marshal the party object.
Also change the XmlElement annotiantion to XmlAttribute in the guest class at the name.

Related

Java - JAXB - Unmarshalling : How to achieve the correct set up?

I'm currently trying to change lots of XML into Java objects but I keep getting stuck. I have tried copying lots of different examples online but I can never seem to get the right way and I find it very hard to debug.
My XML looks like this
<?xml version="1.0" encoding="utf-8"?>
<XMLSOCCER.COM>
<TeamLeagueStanding xmlns="http://xmlsoccer.com/LeagueStanding">
<Team>Leicester</Team>
<Team_Id>31</Team_Id>
<Played>26</Played>
<PlayedAtHome>12</PlayedAtHome>
<PlayedAway>14</PlayedAway>
<Won>15</Won>
<Draw>8</Draw>
<Lost>3</Lost>
<NumberOfShots>464</NumberOfShots>
<YellowCards>40</YellowCards>
<RedCards>1</RedCards>
<Goals_For>48</Goals_For>
<Goals_Against>29</Goals_Against>
<Goal_Difference>19</Goal_Difference>
<Points>53</Points>
</TeamLeagueStanding>
<TeamLeagueStanding xmlns="http://xmlsoccer.com/LeagueStanding">
<Team>Tottenham</Team>
<Team_Id>21</Team_Id>
...
So I just have a list of TeamLeagueStanding s that I want to keep as Team objects. My java code for the Team class is currently like this
#XmlRootElement(name = "TeamLeagueStanding")
public class Team {
#XmlElement(name = "Team")
String teamName;
#XmlElement(name = "Team_Id")
int teamID;
public Team (String team, int id) {
super();
this.teamName = team;
this.teamID = id;
}
}
My Teams class which is just to hold the list of Teams is like this
#XmlRootElement(name = "XMLSOCCER.COM")
public class Teams {
#XmlElement
List<Team> teamList;
public Teams () {
}
}
and my main function is like this
public class Main {
public static void main(String[] args) throws Exception {
File xml = new File("data/GetLeagueStandingsPrem1516.xml");
JAXBContext jc = JAXBContext.newInstance(Teams.class);
Unmarshaller um = jc.createUnmarshaller();
Teams t = (Teams) um.unmarshal(xml);
System.out.println(t.teamList.size());
}
}
I've tried this so many ways and I always get either a null pointer exception or various IllegalAnnotationExceptions. If anyone has any idea where I'm going wrong I would greatly appreciate any pointers!
Thanks,
Simon
I think you should add #XmlAccessorType(XmlAccessType.FIELD) annotation
#XmlRootElement(name = "TeamLeagueStanding")
#XmlAccessorType(XmlAccessType.FIELD)
public class Team {
}
Your root element seems to be XMLSOCCER.COM
1. create xsd
2. using xjc command create java bean classes or you can use IDE to create objects.
3.keep created xml bean objects under src
4. then you pass the xml to be unmarshelled
5. you will get converted objects hierarchically you can access.
Add default constructor to Team class
Add
#XmlElement(name = "TeamLeagueStanding")
List<Team> teamList;
to Teams class;
Team.class:
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement(name = "TeamLeagueStanding")
public class Team {
#XmlElement(name = "Team")
String teamName;
#XmlElement(name = "Team_Id")
int teamID;
public Team (){
}
public Team (String team, int id) {
super();
this.teamName = team;
this.teamID = id;
}
}
Teams.class
import javax.xml.bind.annotation.*;
import java.util.List;
#XmlRootElement(name = "XMLSOCCER.COM")
#XmlAccessorType(XmlAccessType.FIELD)
public class Teams {
#XmlElement(name = "TeamLeagueStanding")
List<Team> teamList;
public Teams () {
}
}

JAXB marshalling and inheritance

I have 2 classes, one extends the other. The superclass marshals correctly, but the subclass, which adds one attribute, does not. The extra attribute is not present in the XML.
Superclass:
#XmlRootElement()
#XmlAccessorType(XmlAccessType.NONE)
public class SessionRecord extends Record {
SimpleDateFormat hhmm = new SimpleDateFormat("HH:mm");
SimpleDateFormat day = new SimpleDateFormat("EEEEE");
#XmlAttribute protected int sessionId;
#XmlAttribute protected boolean open;
#XmlAttribute protected boolean night;
protected Date start;
protected Date finish;
protected boolean setup;
protected boolean takedown;
#XmlAttribute
public String getDescription() {
if (start==null) start = new Date();
if (finish==null) finish = new Date();
return day.format(start)+(night ? " Night " : " ")+hhmm.format(start)+"-"+hhmm.format(finish)+" "+type();
}
private String type() {
return setup ? "Setup" : (open ? "Open" : (takedown ? "Takedown" : ""));
}
#XmlAttribute
public boolean isSetupTakedown() {
return setup || takedown;
}
}
This produces XML elements similar to this:
<sessionRecord setupTakedown="true" description="Saturday 09:00-13:00 Setup" night="false" open="false" sessionId="0"/>
which is OK.
But the subclass:
#XmlRootElement()
public class VolunteerSession extends SessionRecord {
#XmlAttribute private boolean available;
}
Produces identical output, the available attribute is not marshalled. Why is JAXB not marshalling the extra attribute?
EDIT
further information:
Record superclass is merely this:
public abstract class Record {}
Here is the class representing the top-level document element. It contains lists of Records:
#XmlRootElement(name="response")
#XmlSeeAlso({
RecordList.class,
VolunteerAssignment.class,
VolunteerRecord.class,
SessionRecord.class,
VolunteerSession.class,
VolunteerArea.class,
PossibleAssignment.class})
public class XMLResponse {
#XmlAttribute private String errorMessage;
private List<RecordList<? extends Record>> recordLists = new ArrayList<RecordList<? extends Record>>();
//snip...
public void setError(String errorMessage) {
this.errorMessage = errorMessage;
}
#XmlMixed
public List<RecordList<? extends Record>> getRecordLists() {
return recordLists;
}
}
and finally, RecordList
#XmlRootElement()
public class RecordList<T extends Record> {
#XmlAttribute private String name;
#XmlAttribute private int total;
#XmlAttribute private int count;
#XmlAttribute private int start;
#XmlAttribute private boolean update;
private List<T> records;
// snip constructors, setters
#XmlMixed
public List<T> getRecords() {
return records;
}
}
It sounds as though the VolunteerSession class is not being included in the JAXBContext. This can happen depending on how you created your JAXBContext. Below is some example code where the same object is marshalled based on 3 different instances of JAXBContext each bootstrapped off a different class.
import javax.xml.bind.*;
public class Demo {
public static void main(String[] args) throws Exception {
VolunteerSession volunteerSession = new VolunteerSession();
marshal(VolunteerSession.class, volunteerSession);
marshal(SessionRecord.class, volunteerSession);
marshal(XMLResponse.class, volunteerSession);
}
private static void marshal(Class bootstrapClass, Object object) throws Exception {
System.out.println(bootstrapClass.getName());
JAXBContext jc = JAXBContext.newInstance(bootstrapClass);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(object, System.out);
System.out.println();
}
}
Output
When the JAXBContext is bootstrapped off of VolunteerSession obviously it has the necessary information.
When the JAXBContext is bootstraped off of the super class SessionRecord it doesn't pull in VolunteerSession. JAXB will automatically process metadata for super classes, but not subclasses. #XmlSeeAlso is usually used in this case to reference mapped subclasses.
VolunteerRecord contains an #XmlSeeAlso annotation that references VolunteerSession. Therefore VolunteerSession is processed as part of the JAXBContext and contains the necessary information when marshalled.
forum20908213.VolunteerSession
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<volunteerSession available="false" sessionId="0" open="false" night="false" description="Sunday 05:53-05:53 " setupTakedown="false"/>
forum20908213.SessionRecord
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<sessionRecord sessionId="0" open="false" night="false" description="Sunday 05:53-05:53 " setupTakedown="false"/>
forum20908213.XMLResponse
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<volunteerSession available="false" sessionId="0" open="false" night="false" description="Sunday 05:53-05:53 " setupTakedown="false"/>
You have to list all of your subclasses in #XmlSeeAlso annotation of your parent class.

JAXB abstract class with #XmlTransient

I'm using JAXB to unmarshal some xml into an object(s).
I have a class which inherit from an abstract class. I've marked the abstract class as #XmlTransient. Then using XMLType PropOrder I can access the properties in the abstract class like so:
#XmlType( propOrder = { "id"...
Cool. Problem is sometimes it isn't an element that I want to access but rather an attribute. Normally you would define such a property using #XMLAttribute to indicate the value is stored in an xml attribute and not an element. But given the fact that I've already used XMLTransient on the abstract class where 'id' is defined, JAXB complains when I try to mark the field as #XMLAttribute.
JAXB is complaining that I'm trying to access/return two fields of with the same name.
Can anyone please point me in the right direction? I'm building for GAE so I dn't really want to use any other libraries.
Thanks in advance!
Below are a couple of things you can do:
Java Model
Foo
You can annotate the property on the parent class with #XmlAttribute.
import javax.xml.bind.annotation.*;
#XmlTransient
public class Foo {
private String att1;
private String att2;
#XmlAttribute
public String getAtt1() {
return att1;
}
public void setAtt1(String att1) {
this.att1 = att1;
}
public String getAtt2() {
return att2;
}
public void setAtt2(String att2) {
this.att2 = att2;
}
}
Bar
You can override the property on the subclass and annotate it with #XmlAttribute.
import javax.xml.bind.annotation.*;
#XmlRootElement
public class Bar extends Foo {
#Override
#XmlAttribute
public String getAtt2() {
return super.getAtt2();
}
#Override
public void setAtt2(String att2) {
super.setAtt2(att2);
}
}
Demo Code
Demo
Here is some demo code you can run to show that everything works.
import javax.xml.bind.*;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(Bar.class);
Bar bar = new Bar();
bar.setAtt1("a");
bar.setAtt2("b");
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(bar, System.out);
}
}
Output
Below is the output from running the demo code:
<?xml version="1.0" encoding="UTF-8"?>
<bar att1="a" att2="b"/>

JAXB unmarshall to multiple pojo's

I was trying to figure out if it is possible to unmarshall an xml element to multiple pojos. for example:
for xml:
<type>
<id>1</id>
<cost>12</cost>
<height>15</height>
<width>13</width>
<depth>77</depth>
</type>
Item class
#XmlAccessorType(XmlAccessType.PROPERTY)
#XmlRootElement(name="type")
public class Item {
private Integer id;
private Double cost;
#XmlElement(name="id")
public Integer getId(){
return id;
}
#XmlElement(name="cost")
public Double getCost(){
return cost
}
}
ItemDimensions Class
#XmlAccessorType(XmlAccessType.PROPERTY)
#XmlRootElement(name="type")
public class ItemDimensions {
private Integer height;
private Integer width;
private Integer depth;
#XmlElement(name="height")
public Integer getHeight(){
return height;
}
#XmlElement(name="width")
public Integer getWidth(){
return width;
}
#XmlElement(name="depth")
public Integer getDepth(){
return depth;
}
}
I have tried to accomplish something similar using a number of JAXB mappings generated by Netbeans 6.9 and a number of test classes but have gotten nowhwere. Does anyone know if this is something that can be done without any intermediary objects?
You could use the #XmlPath extension in EclipseLink JAXB (MOXy) to accomplish this use case (I'm the MOXy tech lead):
Root
JAXB requires a single object to unmarshal, we will introduce a class to fulfill this role. This class will have fields corresponding to the two Objects you wish to unmarshal annotated with the self XPath: #XmlPath(".")
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlRootElement;
import org.eclipse.persistence.oxm.annotations.XmlPath;
#XmlRootElement(name="type")
#XmlAccessorType(XmlAccessType.FIELD)
public class Root {
#XmlPath(".")
private Item item;
#XmlPath(".")
private ItemDimensions itemDimensions;
}
ItemDimensions
You annotate this class normally. In your example you annotate the properties, but only provide getters. This will cause JAXB to think that those are write only mappings.
import javax.xml.bind.annotation.*;
#XmlAccessorType(XmlAccessType.FIELD)
public class ItemDimensions {
private Integer height;
private Integer width;
private Integer depth;
}
Item
import javax.xml.bind.annotation.*;
#XmlAccessorType(XmlAccessType.FIELD)
public class Item {
private Integer id;
private Double cost;
}
Demo
import java.io.File;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(Root.class);
Unmarshaller u = jc.createUnmarshaller();
Object o = u.unmarshal(new File("input.xml"));
Marshaller m = jc.createMarshaller();
m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
m.marshal(o, System.out);
}
}
jaxb.properties
To use MOXy as your JAXB implementation, you must provide a file named jaxb.properties in with your domain objects with the following entry:
javax.xml.bind.context.factory=org.eclipse.persistence.jaxb.JAXBContextFactory

Simple Java to XML example

I've read a time ago about generate xml from Java using annotations, but I'm not finding a simple example now.
If I want to make a xml file like:
<x:element uid="asdf">value</x:element>
from my java class:
public class Element {
private String uid = "asdf";
private String value = "value";
}
Which annotations should I use to perform that? (I have a xml-schema, if this helps the generation)
--update
The javax.xml.bind.annotation package have the annotations, "but I still haven't found what I'm looking for": an exemple of usage.. :)
Found it:
import java.io.FileOutputStream;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import javax.xml.bind.annotation.XmlRootElement;
public class JavaToXMLDemo {
public static void main(String[] args) throws Exception {
JAXBContext context = JAXBContext.newInstance(Employee.class);
Marshaller m = context.createMarshaller();
m.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
Employee object = new Employee();
object.setCode("CA");
object.setName("Cath");
object.setSalary(300);
m.marshal(object, System.out);
}
}
#XmlRootElement
class Employee {
private String code;
private String name;
private int salary;
public String getCode() {
return code;
}
public void setCode(String code) {
this.code = code;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getSalary() {
return salary;
}
public void setSalary(int population) {
this.salary = population;
}
}
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<employee>
<code>CA</code>
<name>Cath</name>
<salary>300</salary>
</employee>
From: http://www.java2s.com/Code/JavaAPI/javax.xml.bind.annotation/javaxxmlbindannotationXmlRootElement.htm
For the benefit of anyone else hitting this thread, I imagine you did the following:
#XmlRootElement
public class Element {
#XmlAttribute
private String uid = "asdf";
#XmlValue
private String value = "value";
}
For More Information
http://bdoughan.blogspot.com/2011/06/jaxb-and-complex-types-with-simple.html
There are various tools that you can use to do this. XStream (http://x-stream.github.io/) is a reasonably easy tool to use that allows you to use annotations to determine the schema of XML that is created.

Categories