I'm working on a school project where I have to bind some XML values from an API to a java object. I am able to get all the elements, I can't however get the attribute of a specific element. I've looked around for a solution, but couldn't find one.
I have this piece of XML code that I want to unmarshal with JAXB to a Java object. The attribute I would like to get is 'changes' in Departuretrack.
<Departures>
<DepartingTrain>
<Id>220</Id>
<DepartureTime>2017-03-07T11:03:00+0100</DepartureTime>
<DepartureTrack changes="false">5</DepartureTrack>
</DepartingTrain>
<DepartingTrain>
<Id>637</Id>
<DepartureTime>2017-03-07T11:18:00+0100</DepartureTime>
<DepartureTrack changes="false">12</DepartureTrack>
</DepartingTrain>
</Departures>
I do currently have this object, it does work for all the elements. I don't know how to get the attribute 'changes' and put it into this object.
#Entity
#Getter
#Setter
#NoArgsConstructor
#XmlRootElement(name="Departures")
#XmlAccessorType(XmlAccessType.FIELD)
public class Departure {
#Id
#GeneratedValue
private long id;
#XmlElement(name="Id")
private int routeNumber;
#XmlElement(name="DepartureTime")
private String departureTime;
#XmlElement(name="DepartureTrack")
private String departureTrack;
}
I create a list with all the departures with this object.
#Entity
#Getter
#Setter
#NoArgsConstructor
#XmlRootElement(name="Departures")
#XmlAccessorType(XmlAccessType.FIELD)
public class DepartureList {
#Id
#GeneratedValue
private long id;
#XmlElement(name="DepartingTrain")
#OneToMany
private List<Departure> departures = new ArrayList<>();
}
This is what my unmarshaller looks like.
// Returns all departures for a specific station
public DepartureList getDepartingTrains(String station){
try {
URL url = new URL("API URL" + station);
URLConnection urlConnection = url.openConnection();
urlConnection.setRequestProperty("Authorization", "Basic " + authStringEnc);
InputStream is = urlConnection.getInputStream();
InputStreamReader isr = new InputStreamReader(is);
Unmarshaller unmarshaller = departureListJaxbContext.createUnmarshaller();
DepartureList departureList = (DepartureList) unmarshaller.unmarshal(isr);
return departureList;
} catch (JAXBException e) {
e.printStackTrace();
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
// Throw Exception
return null;
}
Does anyone know how to get this attribute from the XML sheet and put it into the Java object?
Add the "changes" attribute under DepartureTrack JAXB Generated class as below:
import javax.xml.bind.annotation.*;
#XmlAccessorType(XmlAccessType.FIELD)
#XmlRootElement
public class DepartureTrack {
#XmlAttribute
protected String changes;
#XmlValue;
protected String content;
}
You should have java classes like below
import org.simpleframework.xml.Attribute;
import org.simpleframework.xml.Element;
import org.simpleframework.xml.ElementList;
import org.simpleframework.xml.Root;
import java.math.BigDecimal;
import java.util.List;
#Root(name = "Departures")
public class Departures {
#ElementList(name = "DepartingTrain", inline = true, required = false)
List<DepartingTrain> departingTrain;
public List<DepartingTrain> getDepartingTrain() { return this.departingTrain; }
public void setDepartingTrain(List<DepartingTrain> _value) { this.departingTrain = _value; }
public static class DepartingTrain {
#Element(name="Id", required = false)
String id;
#Element(name="DepartureTime", required = false)
String departureTime;
#Element(name="DepartureTrack", required = false)
DepartureTrack departureTrack;
public String getId() { return this.id; }
public void setId(String _value) { this.id = _value; }
public String getDepartureTime() { return this.departureTime; }
public void setDepartureTime(String _value) { this.departureTime = _value; }
public DepartureTrack getDepartureTrack() { return this.departureTrack; }
public void setDepartureTrack(DepartureTrack _value) { this.departureTrack = _value; }
}
public static class DepartureTrack {
#Attribute(name="changes", required = false)
Boolean changes;
public Boolean getChanges() { return this.changes; }
public void setChanges(Boolean _value) { this.changes = _value; }
}
}
and there are few sites which provide to create java classes from the xml or json.
http://pojo.sodhanalibrary.com/Convert
http://rnevet.github.io/simple-xml-pojo-gen/
http://pojo.sodhanalibrary.com/pojoFromXSD.html
Related
I have a JSON file that I am trying to convert into XML using the JAXB annotation approach. Everything is working fine now and I able to convert the JSON to XML. Now I am trying to refactor the code a little bit so that my class would look clean. Hence, I am trying to remove the method which is present in my class and make it JAXB XMLAdapter so that it can be reused by other classes.
Basically I would like to move the XMLSupport method from CarInfo class to XMLAdapter. I am not sure how to populate the CarInfo objects when I move them to the XMLAdapter.
Following is my JSON file (it has been modified for simplicity purpose):
{
"brand": "Ferari",
"build": "Italy",
"engine": "Mercedes",
"year": "2021"
}
Following is the XML that I expect JAXB to provide: (Observe the carInfo tag which is not present in JSON but I need in XML to match the standard XSD)
<?xml version="1.0"?>
<Car>
<brand>Ferari</brand>
<build>Italy</build>
<carinfo>
<engine>Mercedes</engine>
<year>2021</year>
</carinfo>
</Car>
Following are the classes that I have: (Tha Car class that matches the JSON elements)
#XmlAccessorType(XmlAccessType.FIELD)
#XmlTransient
#XmlSeeAlso({MyCar.class});
public class Car{
private String brand;
private String build;
#XmlTransient
private String engine;
#XmlTransient
private String year;
//Getter, Setters and other consturctiores ommited
}
Following is MYCar class that builds the XML by adding the carInfo tag:
#XmlAccessorType(XmlAccessType.FIELD)
#XmlRootElement(name = "Car")
#XmlType(name = "Car", propOrder = {"brand","build", "carInfo"})
public class MyCar extends Car{
#XmlElement(name="carInfo")
private CarInfo carInfo;
public MyCar xmlSupport() {
if(carInfo == null){
carInfo = new Carinfo();
}
carInfo.setEngine(getEngine);
carInfo.setYear(getYear());
return this;
}
}
Following is my CarInfo class which acts as a helper to build the additional tag around MyCar class:
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(propOrder = {"engine","year"})
public class Carinfo{
private String engine;
private String year;
//Getter, Setters and other consturctiores ommited
}
Following is my Main class which actually builds the XML by using the JAXBCOntext
public class Main{
public static void main(String[] args){
JAXBContext context = JAXBContext.newInstance(MyCar.class);
Marshaller mar = context.createMarshaller();
mar.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
mar.marshal((MyCar).xmlSupport(), System.out);
System.out.println("-----------------");
}
}
Now coming back to my main question:
As we can see from MyCar class I have the XMLSupport method which is actually populating the CarInfo objects and then using that method I am creating the XML. Is there a way I can move this to XMLAdapter?
I tried creating the XMLAdapter but I am not sure how can I populate the CarInfo objects from the adapter:
public class MyCar extends Car{
#XmlElement(name="carInfo")
#XmlJavaTypeAdapter(ExtensionAdapter.class)
#XmlElement(name = "carInfo")
private CarInfo carInfo;
}
Following is my Adapter class I've tried:
public class ExtensionAdapter extends XmlAdapter<CarInfo, CarInfo> {
#Override
public CarInfo unmarshal(CarInfo valueType) throws Exception {
System.out.println("UN-MARSHALLING");
return null;
}
#Override
public CarInfo marshal(CarInfo boundType) throws Exception {
System.out.println("MARSHALLING");
System.out.println(boundType);
//I get boundType as NULL so I am not sure how to convert the xmlSupport Method to Adapter so I can use this adapter with multiple class
return null;
}
}
You don't need any adapters, you just need a well-defined POJO.
The trick is using getters and setters, not field access, so we can do delegation, and then use #JsonIgnore and #XmlTransient to control which getter/setter methods are used for JSON vs XML.
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlTransient;
import javax.xml.bind.annotation.XmlType;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonPropertyOrder;
#XmlRootElement(name = "Car")
#XmlType(propOrder = { "brand", "build", "carinfo" })
#JsonPropertyOrder({ "brand", "build", "engine", "year" })
public final class Car {
#XmlType(propOrder = { "engine", "year" })
public static final class Info {
private String engine;
private String year;
public String getEngine() {
return this.engine;
}
public void setEngine(String engine) {
this.engine = engine;
}
public String getYear() {
return this.year;
}
public void setYear(String year) {
this.year = year;
}
#Override
public String toString() {
return "Info[engine=" + this.engine + ", year=" + this.year + "]";
}
}
private String brand;
private String build;
private Info carinfo;
public Car() {
// Nothing to do
}
public Car(String brand, String build, String engine, String year) {
this.brand = brand;
this.build = build;
this.carinfo = new Info();
this.carinfo.setEngine(engine);
this.carinfo.setYear(year);
}
public String getBrand() {
return this.brand;
}
public void setBrand(String brand) {
this.brand = brand;
}
public String getBuild() {
return this.build;
}
public void setBuild(String build) {
this.build = build;
}
#JsonIgnore // For XML, not JSON
public Info getCarinfo() {
if (this.carinfo == null)
this.carinfo = new Info();
return this.carinfo;
}
public void setCarinfo(Info info) {
this.carinfo = info;
}
#XmlTransient // For JSON, not XML
public String getEngine() {
return getCarinfo().getEngine();
}
public void setEngine(String engine) {
getCarinfo().setEngine(engine);
}
#XmlTransient // For JSON, not XML
public String getYear() {
return getCarinfo().getYear();
}
public void setYear(String year) {
getCarinfo().setYear(year);
}
#Override
public String toString() {
return "Car[brand=" + this.brand + ", build=" + this.build + ", carinfo=" + this.carinfo + "]";
}
}
Test
Car car = new Car("Ferari", "Italy", "Mercedes", "2021");
// Generate JSON
ObjectMapper jsonMapper = new ObjectMapper();
jsonMapper.enable(SerializationFeature.INDENT_OUTPUT);
String json = jsonMapper.writeValueAsString(car);
// Generate XML
JAXBContext jaxbContext = JAXBContext.newInstance(Car.class);
Marshaller xmlMarshaller = jaxbContext.createMarshaller();
xmlMarshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
String xml;
try (StringWriter writer = new StringWriter()) {
xmlMarshaller.marshal(car, writer);
xml = writer.toString();
}
// Print generated results
System.out.println(car);
System.out.println(json);
System.out.println(xml);
// Parse JSON
Car carFromJson = jsonMapper.readValue(json, Car.class);
System.out.println(carFromJson);
// Parse XML
Unmarshaller xmlUnmarshaller = jaxbContext.createUnmarshaller();
Car carFromXml = xmlUnmarshaller.unmarshal(new StreamSource(new StringReader(xml)), Car.class).getValue();
System.out.println(carFromXml);
Outputs
Car[brand=Ferari, build=Italy, carinfo=Info[engine=Mercedes, year=2021]]
{
"brand" : "Ferari",
"build" : "Italy",
"engine" : "Mercedes",
"year" : "2021"
}
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<Car>
<brand>Ferari</brand>
<build>Italy</build>
<carinfo>
<engine>Mercedes</engine>
<year>2021</year>
</carinfo>
</Car>
Car[brand=Ferari, build=Italy, carinfo=Info[engine=Mercedes, year=2021]]
Car[brand=Ferari, build=Italy, carinfo=Info[engine=Mercedes, year=2021]]
As you can see, the generated JSON and XML is exactly what you wanted, and the last two lines of output shows that parsing works as well.
I want to unmarshal this xml document that I am receiving from a REST call:
<ns2:hello xmlns:ns4="http://myspace.org/hello/history/1.0" xmlns:ns3="http://www.hello.com/IAP/im1_1_0" xmlns:ns2="http://www.w3.org/2005/Atom">
<ns3:totalEntries>7</ns3:totalEntries>
<ns2:id>123</ns2:id>
<ns2:title type="text">Users</ns2:title>
<ns2:updated>2017-08-22T07:51:27.270Z</ns2:updated>
<ns2:link href="https://example.com:8080/1/rest/users" rel="self"/>
<ns2:link href="https://example.com:8080/1/rest/users" rel="http://www.example.com/iap/im/user/create"/>
<ns4:complete/>
<ns2:entry>
<ns2:id>urn:uuid:f0fd4040-04da-11e7-8f6a-8e3ecfcb7035</ns2:id>
<ns2:title type="text">Hello</ns2:title>
<ns2:content type="application/vnd.bosch-com.im+xml">
<ns3:user>
<ns3:id>f0fd4040-04da-11e7-8f6a-8e3ecfcb7035</ns3:id>
<ns3:name>name</ns3:name>
<ns3:firstName>Hello</ns3:firstName>
<ns3:lastName>All</ns3:lastName>
</ns3:user>
</ns2:content>
</ns2:entry>
</ns2:hello>
As you can see the XML is nested, and for this I am using JAXB for unmarshalling:
try {
JAXBContext jc = JAXBContext.newInstance(Feed.class);
Unmarshaller um = jc.createUnmarshaller();
Feed feed = (Feed) um.unmarshal(new StringReader(userEntity.getBody()));
System.out.println(feed.getEntry().get(0).getContent().getUser().getFirstName());
}
catch (JAXBException e) {
e.printStackTrace();
}
But, I am not getting any data set into my POJO (it's null):
#XmlRootElement(namespace="http://www.w3.org/2005/Atom", name="hello")
public class Hello {
private String id;
private String totalEntries;
private String title;
private String updated;
List<Entry> entry;
Complete complete;
}
My POJO looks like above. Also I have created Entry and Complete POJO classes. How can I fix this?
The XML has 3 namespaces:
xmlns:ns4="http://myspace.org/hello/history/1.0"
xmlns:ns3="http://www.hello.com/IAP/im1_1_0"
xmlns:ns2="http://www.w3.org/2005/Atom"
You will need to ensure that each element is in the correct namespace #XmlElement(namespace="xmlns:ns3="http://www.hello.com/IAP/im1_1_0") etc, to be able to unmarshall correctly
You may Also benefit from adding #XmlType(propOrder = { "totalEntries", ...
Have you tried just adding getters and setters to the class Hello ?
Your sample works with this simplified version of Hello.
#XmlRootElement(namespace = "http://www.w3.org/2005/Atom", name = "hello")
public class Hello {
private String id;
private String title;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
}
And the Test class
public class Test {
public static void main(String[] args) {
try {
JAXBContext jc = JAXBContext.newInstance(Feed.class);
Unmarshaller um = jc.createUnmarshaller();
InputStream file = new FileInputStream("path/to/file/feed.xml");
Hello feed = (Hello) um.unmarshal(file);
System.out.println(feed.getId());
System.out.println(feed.getTitle());
} catch (JAXBException | FileNotFoundException e) {
e.printStackTrace();
}
}
}
Prints
123
Users
I've been experimenting with JAXB tutorials and have managed to get code working that generates an XML file from a Java object and then is able to use the XML to generate a Java object. At the moment it reads multiple instances of the same class to create an XML file similar to the one below
<Car>
<regplate>TR54</regplate>
<colour>red</colour>
<energyrating>5</energyrating>
</Car>
<Car>
<regplate>BN04 THY</regplate>
<colour>yellow</colour>
<energyrating>3</energyrating>
</Car>
<Car>
<regplate>BN05 THY</regplate>
<colour>yellow</colour>
<energyrating>5</energyrating>
</Car>
I would like to be able to use the JAXB technology to work with subclasses. For example: Say I have a Car, Van and Bicycle objects that are subclasses of Vehicle. Is it possible for me to manipulate my JAXB class to write an XML file that would produce something similar to this? I have provided the code I am working with below.
<Vehicle>
<Car>
<regplate>TR54</regplate>
<colour>red</colour>
<energyrating>5</energyrating>
</Car>
<Van>
<regplate>MN05 RFD</regplate>
<colour>red</colour>
<energyrating>5</energyrating>
</Van>
<Car>
<regplate>ZX54 UJK</regplate>
<colour>red</colour>
<energyrating>1</energyrating>
</Car>
</Vehicle>
Main Class
package basictransport2;
public class Main
{
public static void main(String[] args)
{
JAXB parser = new JAXB();
parser.marshall();
//parser.unmarshallList();
}
}
Vehicle Class
package basictransport2;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
//#XmlRootElement(name = "Vehicle")
public class Vehicle
{
private int ownerId;
public Vehicle(int ownerId)
{
this.setOwnerId(ownerId);
}
//#XmlElement (name = "Owner ID")
public int getOwnerId()
{
return ownerId;
}
public void setOwnerId(int ownerId)
{
this.ownerId = ownerId;
}
public int getEnergyRating()
{
return (Integer) null;
}
public String getColour()
{
return null;
}
public String getRegPlate()
{
return null;
}
}
Car Class
package basictransport2;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
//#XmlRootElement(name = "Car")
public class Car extends Vehicle
{
private String regPlate;
private int energyRating;
private String colour;
public Car(String regPlate, int energyRating, String colour, int ownerId)
{
super(ownerId);
this.regPlate = regPlate;
this.energyRating = energyRating;
this.colour = colour;
}
public Car(int ownerId)
{
super(ownerId);
}
//#XmlElement (name = "Registration")
public String getRegPlate()
{
return regPlate;
}
public void setRegPlate(String regPlate)
{
if(this.regPlate == null)
{
this.regPlate = regPlate;
}
}
//#XmlElement (name = "Energy Rating")
public int getEnergyRating()
{
return energyRating;
}
public void setEnergyRating(int energyRating)
{
this.energyRating = energyRating;
}
//#XmlElement (name = "Colour")
public String getColour()
{
return colour;
}
public void setColour(String colour)
{
this.colour = colour;
}
}
JAXB Class
package basictransport2;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
public class JAXB
{
public void marshall()
{
try
{
List<Vehicle> vehicleList = new ArrayList<Vehicle>();
vehicleList.add(new Car("SG09 TYH", 4, "Yellow", 1));
vehicleList.add(new Car("XX09 VVV", 3, "Red", 2));
vehicleList.add(new Car("BL09 TYZ", 4, "Blue", 3));
Garage listOfVehicles = new Garage();
listOfVehicles.setListOfVehicles(vehicleList);
JAXBContext context = JAXBContext.newInstance(Garage.class);
Marshaller marshaller = context.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(listOfVehicles, System.out);
marshaller.marshal(listOfVehicles, new File("src\\data\\listcar.xml"));
}
catch(Exception e)
{
System.out.println(e.getMessage());
}
}
public void unmarshall()
{
try
{
JAXBContext context = JAXBContext.newInstance(Garage.class);
Unmarshaller unmarhsaller = context.createUnmarshaller();
Garage listOfVehicles = (Garage)unmarhsaller.unmarshal(new File("src\\data\\listcar.xml"));
System.out.println("List Car information");
for(Vehicle vehicle : listOfVehicles.getListOfVehicles())
{
System.out.println("Reg Plate: " + vehicle.getRegPlate());
System.out.println("Energy Rating: " + vehicle.getEnergyRating());
System.out.println("Colour: " + vehicle.getColour());
System.out.println("================");
}
}
catch (Exception e)
{
System.out.println(e.getMessage());
}
}
}
List class
package basictransport2;
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.XmlElements;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlSeeAlso;
import javax.xml.bind.annotation.XmlType;
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name="Vehicle")
public class Garage
{
#XmlElements
({
#XmlElement(name = "Car", type = Car.class, required = false)
})
private List<Vehicle> vehicleCollection = new ArrayList<Vehicle>();
public List<Vehicle> getListOfVehicles()
{
return vehicleCollection;
}
public void setListOfVehicles(List<Vehicle> listOfVehicles)
{
this.vehicleCollection = listOfVehicles;
}
}
Thanks everyone for your input. I used feedback from all your answers but ultimately it was a combination of them that worked which is why I created a seperate answer for anyone who may have this problem in the future.
To get this to work I had to ensure that all getter methods within the super and sub classes being marhsalled/unmarshalled were annotated with #XmlElement. This would determine the XML tag for the corresponding variable.
#XmlElement (name = "OwnerID")
public int getOwnerId()
{
return ownerId;
}
The superclass had to be annotated with #XmlSeeAlso to bind the subclasses to it. i.e In my code RoadVehicle was the superclass and both the Car and Van classes extended it.
#XmlSeeAlso({Car.class, Van.class})
public class Vehicle
{
With the super and subclasses now annotated the only other class that required annotations was the list class (Garage in my code). The changes here would determine what the XML tags were populated with.
The root XML tag was set by applying the #XmlRootElement annotation to the top of the class. i.e. "Vehicle" would be the root XML tag in my example.
#XmlRootElement(name = "Vehicle")
public class Garage
{
Finally an #XmlElements list had to be declared with an #XmlElements annotation for each sub class that required an XML tag with the name supplying the name of the XML tag. This list had to be declared above the getter method for the collection.
#XmlElements
({
#XmlElement(name = "Car", type = Car.class, required = false),
#XmlElement(name = "Van", type = Van.class, required = false)
})
public List<Vehicle> getListOfVehicles()
{
return vehicleCollection;
}
you are on right track. May something below will help
#XmlRootElement(name = "car")
public class Car extends BasicType{
}
#XmlRootElement(name = "van")
public class Van extends BasicType{
}
#XmlRootElement(name = "vehicle")
public class Vehicle {
List<BasicType> basicType;
}
The simplest solution is to have different subclasses for cars and vans, even it they don't add anything to the base classes. Then, the root element class contains a list of the base class, with element QNames identifying the actual class.
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "Vehicle")
public class Vehicle {
#XmlElements({
#XmlElement(name = "Car", type = Car.class, required = false),
#XmlElement(name = "Van", type = Van.class, required = false)
})
protected List carOrVan;
public List getCarOrVan() {
if (carOrVan == null) {
carOrVan = new ArrayList();
}
return this.carOrVan;
}
}
Here's the base class and the subclasses:
public class Basic {
private String regplate;
private String color;
private String energyrating;
public String getRegplate(){ return regplate; }
public void setRegplate( String v ){ regplate = v; }
public String getColor(){ return color; }
public void setColor( String v ){ color = v; }
public String getEnergyrating(){ return energyrating; }
public void setEnergyrating( String v ){ energyrating = v; }
}
public class Car extends Basic {}
public class Van extends Basic {}
This will go smoothly if cars and vans develop into distinct subclasses.
From an XQuery performed by BaseX server I get a result like that:
<ProtocolloList>
<protocollo>
<numero>1</numero>
<data>2014-06-23</data>
<oggetto/>
<destinatario/>
<operatore/>
</protocollo>
...
</ProtocolloList>
And I need to convert this result in a List of Protocollo objects with JAXB so that I can show them with JList. Thus, following one of the discussions here I've declared the following classes:
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement(name = "protocollo")
public class Protocollo {
private int numero;
private String data;
private String oggetto;
private String destinatario;
private String operatore;
public Protocollo(String d, String o, String des, String op) {
this.data = d;
this.oggetto = o;
this.destinatario = des;
this.operatore = op;
}
public Protocollo() {
}
#XmlElement
public int getNumero() {
return numero;
}
public void setNumero(int numero) {
this.numero = numero;
}
#XmlElement
public String getData() {
return data;
}
public void setData(String data) {
this.data = data;
}
#XmlElement
public String getOggetto() {
return oggetto;
}
public void setOggetto(String oggetto) {
this.oggetto = oggetto;
}
#XmlElement
public String getDestinatario() {
return destinatario;
}
public void setDestinatario(String destinatario) {
this.destinatario = destinatario;
}
#XmlElement
public String getOperatore() {
return operatore;
}
public void setOperatore(String operatore) {
this.operatore = operatore;
}
}
and
import java.util.ArrayList;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement(name = "ProtocolloList")
public class ProtocolloList {
#XmlElementWrapper(name = "ProtocolloList")
#XmlElement(name = "protocollo")
private ArrayList<Protocollo> ProtocolloList;
public ArrayList<Protocollo> getProtocolloList() {
return ProtocolloList;
}
public void setProtocolloList(ArrayList<Protocollo> protocolloList) {
ProtocolloList = protocolloList;
}
}
and finally I execute the converion like that:
JAXBContext jaxbContext = JAXBContext.newInstance(Protocollo.class);
Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
StringReader reader = new StringReader(this.resultXML);
protocolli = (ProtocolloList) unmarshaller.unmarshal(reader);
And I keep on getting this exception:
unexpected element (uri:"", local:"ProtocolloList"). Expected elements are <{}protocollo>
I suppose I'm making some mistakes with annotations.
Can you help?
For your use case you do not need the #XmlElementWrapper annotation. This is because the ProtocolList element corresponds to your #XmlRootElement annotation. Then you need the #XmlElement annotation on the property to grab each of the list items.
#XmlRootElement(name = "ProtocolloList")
public class ProtocolloList {
private ArrayList<Protocollo> ProtocolloList;
#XmlElement(name = "protocollo")
public ArrayList<Protocollo> getProtocolloList() {
return ProtocolloList;
}
}
Note:
By default you should annotate the property. If you want to annotate the fields you should put #XmlAccessorType(XmlAccessType.FIELD) on your class.
UPDATE
You need to make sure your JAXBContext is aware of the root class. You can change your JAXBContext creation code to be the following:
JAXBContext jaxbContext = JAXBContext.newInstance(ProtocolloList.class);
I have created an object which maps two tables in my database, the Dictionary table and the Token table. The object (class) that represents the join between these two tables is called DictionaryToken.
Here is the class:
import java.util.List;
import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.FetchType;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Table;
import org.apache.log4j.Logger;
#Entity
#Table(name="dictionary", catalog="emscribedxcode")
public class DictionaryToken {
private static Logger LOG = Logger.getLogger(DictionaryToken.class);
private Long _seq;
private String _code;
private String _acute;
private String _gender;
private String _codeType;
private String _papplydate;
private String _capplydate;
private Long _tokenLength;
private List <TokenDictionary> _token;
private int _type;
private String _system;
private String _physicalsystem;
/*
* type of 0 is a straight line insert type of 1 is a language dictionary
* entyr type of 2 is a multiple token entry
*/
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
#Column(name = "seq")
public Long getSeq() {
return _seq;
}
public void setSeq(Long seq_) {
_seq = seq_;
}
#Column(name = "code")
public String getCode() {
return _code;
}
public void setCode(String code_) {
_code = code_;
}
#Column(name = "acute")
public String getAcute() {
return _acute;
}
public void setAcute(String acute_) {
_acute = acute_;
}
#Column(name = "gender")
public String getGender() {
return _gender;
}
public void setGender(String gender_) {
_gender = gender_;
}
#Column(name = "codetype")
public String getCodeType() {
return _codeType;
}
public void setCodeType(String codeType_) {
_codeType = codeType_;
}
#Column(name = "papplydate")
public String getPapplydate() {
return _papplydate;
}
public void setPapplydate(String papplydate_) {
_papplydate = papplydate_;
}
#Column(name = "capplydate")
public String getCapplydate() {
return _capplydate;
}
public void setCapplydate(String capplydate_) {
_capplydate = capplydate_;
}
#Column(name = "token_length")
public Long getTokenLength() {
return _tokenLength;
}
public void setTokenLength(Long tokenLength_) {
_tokenLength = tokenLength_;
}
#OneToMany (mappedBy = "dictionarytoken", targetEntity = TokenDictionary.class, cascade = CascadeType.ALL, fetch = FetchType.EAGER)
public List<TokenDictionary> get_token() {
return _token;
}
public void set_token(List<TokenDictionary> _token) {
this._token = _token;
}
public void addToToken(TokenDictionary token){
this._token.add(token);
}
#Column(name = "type")
public int getType() {
return _type;
}
public void setType(int _type) {
this._type = _type;
}
#Column(name = "physicalsystem")
public String get_physicalsystem() {
return _physicalsystem;
}
public void set_physicalsystem(String _physicalsystem) {
this._physicalsystem = _physicalsystem;
}
#Column(name = "codingsystem")
public String get_system() {
return _system;
}
public void set_system(String _system) {
this._system = _system;
}
}
Here is my problem. I can perform queries using a service with this object with no problems UNLESS I add a criteria. Here is the method which retrieves the entries
public List<DictionaryToken> getDictionaryTokenEntries(String system) {
Session session = null;
List<DictionaryToken> dictonaries = new ArrayList<DictionaryToken>();
try {
session = HibernateUtils.beginTransaction("emscribedxcode");
session.createCriteria(Dictionary.class).addOrder(Order.desc("codeType"))
Criteria criteria = session.createCriteria(DictionaryToken.class);
/*******THIS IS THE PROBLEM STATEMENT*************************/
if (system != null) {
criteria.add(Restrictions.eq("codingsystem", system));
}
/****************************************************************/
// dictonaries = criteria.list();
Order order = Order.asc("seq");
criteria.addOrder(order);
dictonaries = criteria.list();
System.out.println("Dictionaryentries = " + dictonaries.size());
// System.out.println("Dictionaries entries EVICT start...");
// for(Dictionary dic : dictonaries){
// session.evict(dic);
// }
// System.out.println("Dictionaries entries EVICT end");
} catch (HibernateException e_) {
e_.printStackTrace();
NTEVENT_LOG.error("Error while getting List of Dictionary entries");
} finally {
if (session != null && session.isOpen()) {
try {
HibernateUtils.closeSessions();
} catch (HibernateException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
return dictonaries;
}
When I add the criteria, I get the following error:
org.hibernate.QueryException: could not resolve property: coding system of : com.artificialmed.domain.dictionary.model.DictionaryToken
I know that it has something to do with the nature of the object which is really a join between my dictionary class and the underlying table and my token class and table.
The field codingsystem is a field in my dictionary class. I think I am suppose to use aliases but I don't know how to do this under the current circumstances. Any help would be greatly appreciated.
Elliott
This was a newbie problem. Hibernate requires the getters and setters of the models that reflect the tables to be of a specific format. The getter MUST BE get+ where name is the fieldname in the underlying table. The setter MUST BE set+ where name is the fieldname of the underlying table. And yes the first letter of Name must capitalized.