JAXB super class field not being deserialized - java

I am trying to deserialize xml string into object but ran across strange problem. Everything is being serialized as intended, however when deserializing field which originates from parent class always returns null.
MyNffgDescriptor is a class which contain VNFTypeReader as attribute. All fields are deserialized correctly, VNFTypeReader ones as well except the name which is passed from parent class (NamedEntityReaderImpl) and it returns null.
Parent class
package it.polito.dp2.NFV.sol3.client1.implementations;
import java.io.Serializable;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import it.polito.dp2.NFV.NamedEntityReader;
#XmlAccessorType(XmlAccessType.NONE)
public class NamedEntityReaderImpl implements NamedEntityReader, Serializable {
/**
*
*/
private static final long serialVersionUID = 1L;
private String entityName;
public NamedEntityReaderImpl() {
this.entityName = "";
}
public NamedEntityReaderImpl(String name) {
this.entityName = name;
}
#Override
public String getName() {
return this.entityName;
}
}
Child class
package it.polito.dp2.NFV.sol3.client1.implementations;
import java.io.Serializable;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import it.polito.dp2.NFV.VNFTypeReader;
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
public class VNFTypeReaderImpl extends NamedEntityReaderImpl implements Serializable,VNFTypeReader {
/**
*
*/
private static final long serialVersionUID = 1L;
#XmlElement
private int requiredMemory;
#XmlElement
private int requiredStorage;
#XmlElement
private it.polito.dp2.NFV.FunctionalType funcType;
public VNFTypeReaderImpl() {
super(null);
this.requiredMemory = 0;
this.requiredStorage = 0;
this.funcType = null;
}
public VNFTypeReaderImpl(VNFTypeReader reader) {
super(reader.getName());
this.requiredMemory = reader.getRequiredMemory();
this.requiredStorage = reader.getRequiredStorage();
this.funcType = reader.getFunctionalType();
}
#Override
public int getRequiredMemory() {
return this.requiredMemory;
}
#Override
public int getRequiredStorage() {
return this.requiredStorage;
}
#Override
public it.polito.dp2.NFV.FunctionalType getFunctionalType() {
return this.funcType;
}
#Override
#XmlElement(name="name", required=true)
public String getName() {
return super.getName();
}
}
This is the example of xml string I am trying to deserialize:
<?xml version="1.0" encoding="UTF-8"?>
<myNffgDescriptor>
<nodeList id="0">
<funcReader>
<requiredMemory>620</requiredMemory>
<requiredStorage>100</requiredStorage>
<funcType>WEB_SERVER</funcType>
<name>WEBSERVERt</name>
</funcReader>
<hostName>H3</hostName>
<linksList source="0" destination="10" />
<linksList source="0" destination="11" />
<linksList source="0" destination="8" />
</nodeList>
</myNffgDescriptor>
Place where unmarshalling occurs:
jaxbContext = JAXBContext.newInstance(MyNffgDescriptor.class);
unmarshaller = jaxbContext.createUnmarshaller();
StringReader reader = new StringReader(nffg);
MyNffgDescriptor nffgDesc = (MyNffgDescriptor) unmarshaller.unmarshal(reader);

Change XmlAccessType.NONE to XmlAccessType.FIELD on parent
class NamedEntityReaderImpl.
Also you could just add on class NamedEntityReaderImpl an annotation above the field:
#XmlElement(name= "name")
private String entityName;
Do either changes (or both) and it would work

Related

Marshalling/Unmarshalling Java superclass and subclasses using JAXB

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.

How to avoid root element annotation while marshalling in JAXB?

I want to store my object data to XML. Below code spinets will show the example of model class.
Class Model
{
#XmlElement
private int id;
#XmlElement
Private string name;
}
I will have multiple model objects which will be stored in some list as below
#XmlRootElement
Class ModelWrapper
{
#XmlElement
#XmlJavaTypeAdapter(value = ListAdapter.class, type = List.class)
List<model> list;
public setlist(List<model>list)
{
//setting list
}
public List<model> getlist()
{
return list
}
}
Now if I marshall this using JAXB, something like this will be produced:
<Modelwrapper>
<List>
......
......
</List>
</Modelwrapper>
I want to avoid one of the root may be list or Modelwrapper.
Is there any way to do it?
In this way your xml will be
<ModelWrapper>
<model>
......
</model>
<model>
......
</model>
</ModelWrapper>
ModelWrapper.java
#XmlRootElement
public class ModelWrapper {
#XmlElement(name = "model")
protected List<Model> list;
Test
ModelWrapper.java
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;
import javax.xml.bind.annotation.XmlType;
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "ModelWrapper", propOrder = {
"list"
})
public class ModelWrapper {
#XmlElement(name = "model")
private List<Model> list;
public List<Model> getList() {
return list;
}
public void setList(List<Model> list) {
this.list = list;
}
}
Model.java
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlType;
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "Model", propOrder = {
"id","name"
})
public class Model {
#XmlElement
private int id;
#XmlElement
private String name;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Main.java
import java.util.ArrayList;
import java.util.List;
import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
public class Main {
public static void main(String[] args) throws JAXBException {
JAXBContext jc = JAXBContext.newInstance(ModelWrapper.class);
ModelWrapper mw = new ModelWrapper();
List<Model> list = new ArrayList<Model>();
Model m = new Model();
m.setId(1);
m.setName("model1");
list.add(m);
m = new Model();
m.setId(1);
m.setName("model2");
list.add(m);
mw.setList(list);
Marshaller mar = jc.createMarshaller();
mar.marshal(mw, System.out);
}
}
Output
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<modelWrapper>
<model>
<id>1</id>
<name>model1</name>
</model>
<model>
<id>1</id>
<name>model2</name>
</model>
</modelWrapper>

Why does play.libs.Json.toJson return an empty object?

Why can't I convert my Person object into Json?
My Person Model:
#Entity
public class Person extends Model {
#Id
private Long id;
private String value;
}
A controller method:
import com.fasterxml.jackson.databind.JsonNode;
import models.Person;
import play.Logger;
import play.db.ebean.Model;
import play.mvc.Controller;
import play.mvc.Result;
import views.html.index;
import java.util.List;
import static play.data.Form.form;
import static play.libs.Json.toJson;
...
public static Result getJsonPersons() {
List<Person> persons = new Model.Finder(Long.class, Person.class).all();
JsonNode jsonNode = toJson(persons);
Logger.debug("JSON > "+jsonNode.toString());
return ok(jsonNode);
}
Action route:
GET /persons controllers.Application.getJsonPersons()
Resulting JSON returned by the controller method:
[{},{},{},{},{}]
Your problem is related with field access modifiers in the Person class. Both fields are private hence play.libs.Json.toJson cannot access them. You have to provide appropriate getter methods or make these field public.
#Entity
public class Person extends Model {
#Id
private Long id;
private String value;
public Long getId() {
return id;
}
public String getValue() {
return value;
}
}

JAXB - Unexpected elements in XML output

I have a class called Building.
It has a list of BuildingBenchAssociation records (List<BuildingBenchAssociation> benches)
BuildingBenchAssociation has a composite id made up of buildingId and benchId
The ID is represented by separate class called BuildingBenchAssociationPKwhich has only two properties - buildingId and benchId
This is the output I get when I marshal a Building instance
<building buildingId="9">
<benches>
DOMRecord(<?xml version="1.0" encoding="UTF-8"?><buildingBenchAssociation><benchId>245865</benchId><buildingId>9</buildingId></buildingBenchAssociation>)
</benches>
<benches>
DOMRecord(<?xml version="1.0" encoding="UTF-8"?><buildingBenchAssociation><benchId>245866</benchId><buildingId>9</buildingId></buildingBenchAssociation>)
</benches>
<benches>
But I don't want DOMRecord(<?xml version="1.0" encoding="UTF-8"?> to appear in the output. Required output is something like this:
<building buildingId="9">
<benches>
<buildingBenchAssociation><benchId>245865</benchId><buildingId>9</buildingId></buildingBenchAssociation>
</benches>
<benches>
<buildingBenchAssociation><benchId>245866</benchId><buildingId>9</buildingId></buildingBenchAssociation>
</benches>
<benches>
What's wrong and how do I correct it? I am using the Eclipselink MOXy library.
Classes for reference:
Class 1
#Entity
#Table(name="building")
#XmlRootElement
public class Building implements Serializable {
....
private List<BuildingBenchAssociation> benchs = new ArrayList<BuildingBenchAssociation>();
#XmlIDREF
#OneToMany(mappedBy="building")
public List<BuildingBenchAssociation> getBenchs() {
return benchs;
}
public void setBenchs(List<BuildingBenchAssociation> benchs) {
this.benchs = benchs;
}
}
Class 2
#Entity
#Table(name="building_bench_rel")
#XmlRootElement
public class BuildingBenchAssociation implements Serializable {
private static final long serialVersionUID = 1L;
private BuildingBenchAssociationPK idx;
private Bench bench;
private Building building;
private byte alertFlags;
private byte status;
public BuildingBenchAssociation() {
idx=new BuildingBenchAssociationPK();
}
#XmlID
#XmlPath(".")
#Id
public BuildingBenchAssociationPK getIdx() {
return this.idx;
}
public void setIdx(BuildingBenchAssociationPK id) {
this.idx = id;
}
#Column(name="ALERT_FLAGS")
public byte getAlertFlags() {
return this.alertFlags;
}
public void setAlertFlags(byte alertFlags) {
this.alertFlags = alertFlags;
}
#Column(name="STATUS", insertable=false, updatable=false)
public byte getStatus() {
return this.status;
}
public void setStatus(byte status) {
this.status = status;
}
#XmlIDREF
#ManyToOne
#JoinColumn(name="BENCH_ID",insertable=false,updatable=false)
public Bench getBench() {
return bench;
}
public void setBench(Bench bench) {
this.bench = bench;
this.idx.setBenchId(bench==null?null:bench.getBenchId());
}
#XmlIDREF
#ManyToOne
#JoinColumn(name="BUILDING_ID",insertable=false,updatable=false)
public Building getBuilding() {
return building;
}
public void setBuilding(Building building) {
this.building = building;
this.idx.setBuildingId(building==null?null:building.getBuildingId());
}
}
Class 3
#Embeddable
#XmlRootElement
public class BuildingBenchAssociationPK implements Serializable {
...
private Integer buildingId;
private Integer benchId;
public BuildingBenchAssociationPK() {
}
#XmlKey
#Column(name="BUILDING_ID")
public Integer getBuildingId() {
return this.buildingId;
}
public void setBuildingId(Integer buildingId) {
this.buildingId = buildingId;
}
#XmlKey
#Column(name="BENCH_ID")
public Integer getBenchId() {
return this.benchId;
}
public void setBenchId(Integer benchId) {
this.benchId = benchId;
}
}
Below is how you can currently map this use case using MOXy. I have opened the following enhancement request to make this use case easier to map:
http://bugs.eclipse.org/407460
REFERENCED OBJECT
Embedded ID (EmployeeId)
Below is an example of an embedded ID class:
import java.math.BigDecimal;
import javax.persistence.*;
import javax.xml.bind.annotation.*;
#Embeddable
#XmlAccessorType(XmlAccessType.FIELD)
public class EmployeeId {
#Column(name="E_ID")
BigDecimal eId;
String country;
}
Class with Embedded ID (Employee)
We want to use the embedded ID class for as the key in an XML relationship. Currently MOXy does not allow this to be done via annotations, so we will leverage the #XmlCustomizer annotation to programmatically modify the metadata.
import java.util.List;
import javax.persistence.*;
import javax.xml.bind.annotation.*;
import org.eclipse.persistence.oxm.annotations.*;
#Entity
#IdClass(EmployeeId.class)
#XmlRootElement
#XmlAccessorType(XmlAccessType.FIELD)
#XmlCustomizer(EmployeeCustomizer.class)
public class Employee {
#EmbeddedId
#XmlPath(".")
EmployeeId id;
#OneToMany(mappedBy="contact")
List<PhoneNumber> contactNumber;
}
Customize Mapping Metadata for Employee (EmployeeCustomizer)
In the customizer class we will specify the XPaths for the mappings that compose the key on the embedded class.
import org.eclipse.persistence.config.DescriptorCustomizer;
import org.eclipse.persistence.descriptors.ClassDescriptor;
public class EmployeeCustomizer implements DescriptorCustomizer {
#Override
public void customize(ClassDescriptor descriptor) throws Exception {
descriptor.addPrimaryKeyFieldName("eId/text()");
descriptor.addPrimaryKeyFieldName("country/text()");
}
}
REFERRING OBJECT
PhoneNumber
We are also going to need to programatically add the mapping based on the composite key, so once again we will use the #XmlCustomizer annotation.
import javax.persistence.*;
import javax.xml.bind.annotation.*;
import org.eclipse.persistence.oxm.annotations.*;
#Entity
#XmlAccessorType(XmlAccessType.FIELD)
#XmlCustomizer(PhoneNumberCustomizer.class)
public class PhoneNumber {
#ManyToOne
#JoinColumns({
#JoinColumn(name="E_ID", referencedColumnName = "E_ID"),
#JoinColumn(name="E_COUNTRY", referencedColumnName = "COUNTRY")
})
Employee contact;
}
Customize Mapping Metadata for PhoneNumber (PhoneNumberCustomizer)
In this customizer we will remove the default mapping, and programatically create the new one based on the composite keys.
import org.eclipse.persistence.config.DescriptorCustomizer;
import org.eclipse.persistence.descriptors.ClassDescriptor;
import org.eclipse.persistence.oxm.mappings.XMLObjectReferenceMapping;
public class PhoneNumberCustomizer implements DescriptorCustomizer {
#Override
public void customize(ClassDescriptor descriptor) throws Exception {
descriptor.removeMappingForAttributeName("contact");
XMLObjectReferenceMapping contactMapping = new XMLObjectReferenceMapping();
contactMapping.setAttributeName("contact");
contactMapping.setReferenceClass(Employee.class);
contactMapping.addSourceToTargetKeyFieldAssociation("contact/#eID", "eId/text()");
contactMapping.addSourceToTargetKeyFieldAssociation("contact/#country", "country/text()");
descriptor.addMapping(contactMapping);
}
}
DEMO CODE
The following demo code can be used to demonstrate that everything works:
Demo
import java.io.File;
import javax.xml.bind.*;
public class Demo {
public static void main(String[] args) throws Exception {
JAXBContext jc = JAXBContext.newInstance(Employee.class);
Unmarshaller unmarshaller = jc.createUnmarshaller();
File xml = new File("input.xml");
Employee employee = (Employee) unmarshaller.unmarshal(xml);
Marshaller marshaller = jc.createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, true);
marshaller.marshal(employee, System.out);
}
}
input.xml/Output
<?xml version="1.0" encoding="UTF-8"?>
<employee>
<eId>10</eId>
<country>Canada</country>
<contactNumber>
<contact eID="10" country="Canada"/>
</contactNumber>
<contactNumber>
<contact eID="10" country="Canada"/>
</contactNumber>
</employee>
FOR MORE INFORMATION
http://wiki.eclipse.org/EclipseLink/Examples/MOXy/JPA/EmbeddedIdClass

parsing subnodes with Jersey

We are connecting to a third party using Jersey. We then want to extract the returned xml into our class. This is actually working fine except for one node in the xml that is in a subnode.
Here is the xml returned:
<response>
...
<langISO>en</langISO>
<acquirerAmount>1000</acquirerAmount>
<acquirerCurrency>GBP</acquirerCurrency>
<subXml>
<authCode>122958</authCode>
</subXml>
</response>
Note that the authCode node is in a subnode (called subXml).
OurResponse myriadResponse = response.getEntity(OurResponse.class);
Here is our class, but it is not parsing out the authCode
package com.xxx;
import javax.ws.rs.Consumes;
import javax.ws.rs.Path;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement
#Consumes("application/xml")
public class OurResponse {
private String authCode;
#XmlElement(name = "subXml/authCode")
public String getAuthCode() {
return authCode;
}
#XmlElement(name = "subXml/authCode")
public void setAuthCode(String authCode) {
this.authCode = authCode;
}
}
You have a couple different options:
Option 1 - MOXy JAXB & #XmlPath
You could use the MOXy JAXB implementation and the #XmlPath extension to achieve the desired result:
import javax.xml.bind.annotation.XmlRootElement;
import org.eclipse.persistence.oxm.annotations.XmlPath;
#XmlRootElement(name="response")
public class OurResponse {
private String authCode;
#XmlPath("subXml/authCode/text()")
public String getAuthCode() {
return authCode;
}
public void setAuthCode(String authCode) {
this.authCode = authCode;
}
}
For more information see:
http://bdoughan.blogspot.com/2010/09/xpath-based-mapping-geocode-example.html
Option 2 - Any JAXB Impl and #XmlJavaTypeAdapter
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
#XmlRootElement(name="response")
public class OurResponse {
private String authCode;
#XmlJavaTypeAdapter(AuthCodeAdapter.class)
#XmlElement(name="subXml")
public String getAuthCode() {
return authCode;
}
public void setAuthCode(String authCode) {
this.authCode = authCode;
}
}
with
import javax.xml.bind.annotation.adapters.XmlAdapter;
public class AuthCodeAdapter extends XmlAdapter<SubXml, String> {
#Override
public String unmarshal(SubXml v) throws Exception {
return v.getAuthCode();
}
#Override
public SubXml marshal(String v) throws Exception {
SubXml subXml = new SubXml();
subXml.setAuthCode(v);
return subXml;
}
}
and
public class SubXml {
private String authCode;
public String getAuthCode() {
return authCode;
}
public void setAuthCode(String authCode) {
this.authCode = authCode;
}
}
For more information see:
http://bdoughan.blogspot.com/2010/07/xmladapter-jaxbs-secret-weapon.html
I don't think you can annotate with XmlElement like that. You might need to create a seperate SubXml class;
import javax.xml.bind.annotation.XmlRootElement;
#XmlRootElement(name="response")
public class OurResponse
{
private String lang;
private String amt;
private String curr;
private SubXml subXml;
public OurResponse()
{
}
//Getters and setters
}
and
public class SubXml
{
private String authcode;
public SubXml()
{
}
public String getAuthcode()
{
return authcode;
}
public void setAuthcode(String authcode)
{
this.authcode = authcode;
}
}
Note that the only annotation you need is #XmlRootElement on the OurResponse class and you need to set the name; name="response".

Categories

Resources