When I try to marshall to XML with nulls for Field1.code and Field2.description I have strange result.
import javax.xml.bind.annotation.\*;
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(propOrder = {
"id",
"fields",
"result",
"comment"
})
#XmlRootElement(name = "response")
public class MyXML {
#XmlElement(required = true)
private String id;
#XmlElement(required = true)
private MyXML.Fields fields;
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(propOrder = {
"field1",
"field2"
})
public static class Fields {
#XmlElement(required = true)
private MyXML.Fields.Field1 field1;
#XmlElement(required = true)
private MyXML.Fields.Field2 field2;
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(propOrder = {
"code"
})
public static class Field1 {
#XmlValue
private Integer code;
#XmlAttribute
private String name;
}
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(propOrder = {
"description"
})
public static class Field2 {
#XmlValue
private String description;
#XmlAttribute
private String name;
}
}
}
Result:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<response>
<id>12345</id>
<fields>
<field1 name="name1"/>
<field2 name="name2">null</field2>
</fields>
</response>
For some reason JAXB serialize null for String type and doesnt serialize null for Integer.
I want to see null in field1 as on field2.
I tried to set nillable=true, but it didn't help.
Related
In the below code, I am expecting the attributes in the order of properties defined, but not able to get it. The order is always mixed up.
Parent Tag
#JacksonXmlRootElement
public class ParentSpec{
#JacksonXmlProperty(localName = "parentSpec")
#JacksonXmlElementWrapper
public MySpec mySpec;
}
ChildTag
public class MySpec {
#JacksonXmlProperty(localName = "mySpec")
#JacksonXmlElementWrapper(useWrapping = false)
public List<MyData> myDataList;
}
Error Child
#JsonPropertyOrder({"id", "type", "name", "data"})
public class MyData{
#JacksonXmlProperty(isAttribute = true)
public String id;
#JacksonXmlProperty(isAttribute = true)
public String type;
#JacksonXmlProperty(isAttribute = true)
public String name;
#JacksonXmlProperty(isAttribute = true)
public String data;
//Other Pojo
}
I tried using the #JsonPropertyOrder, but it works only for elements it seems.
I'm developing an SOAP client and I'm looking for more sophisticated solution to marshalling objects into XML-string using Jaxb2 library.
The goal is to marshall an object, which acts as a wrapper for any-type element. Example:
<Action id="5">
<Employee id="10">
<Name>John</Name>
</Employee>
</Action>
or.
<Action id="5">
<Department id="ABC">
<Name>Economy Department</Name>
<ParentId>CDE</ParentId>
</Department>
</Action>
Note: The xml root (Action) contains either "Employee" or "Department" or anything else.
My current working solution is as follows:
#XmlRootElement(name = "Action")
abstract class Action {
#XmlAttribute(name = "id")
protected String id;
}
class EmployeeAction extends Action {
#XmlElement(name = "Employee")
protected Employee employee;
}
class DepartmentAction extends Action {
#XmlElement(name = "Department")
protected Department department;
}
This works fine, but I'm looking for more universal solution, without the need to create class for each type (*Action extends Action). Name of the element must always be the same as the className of the (dynamic) type. My idea is something like this:
public class Action<T> {
#XmlAttribute(name = "id")
protected String id;
#XmlElement(name = "getClass().getSimpleName()") //???
protected T element;
}
... and marshalling something like:
Action<?> action = ...;
JAXBContext context = JAXBContext.newInstance(Action.class, action.getElement().getClass());
Marshaller marshaller = context.createMarshaller();
try(ByteArrayOutputStream outStream = new ByteArrayOutputStream()) {
marshaller.marshal(action, outStream);
return outStream.toString();
}
Is something like this possible?
Thanks in advance.
You can do something like this for the above-provided XML:
METHOD-1
Action.class;
#XmlRootElement(name = "Action")
#Data
#XmlAccessorType(XmlAccessType.FIELD)
public class Action {
#XmlAttribute(name = "id")
protected String id;
#XmlElements({
#XmlElement(name = "Employee", type = Employee.class),
#XmlElement(name = "Department", type = Department .class),
})
private ActionItem type;
}
ActionItem.class;
#Data
#XmlAccessorType(XmlAccessType.NONE)
public class ActionItem {
#XmlElement(name = "Name")
protected String name;
}
Employee.class;
#Data
#XmlAccessorType(XmlAccessType.NONE)
public class Employee extends ActionItem {
#XmlAttribute(name = "id")
private String id;
}
Department.class;
#Data
#XmlAccessorType(XmlAccessType.NONE)
public class Department extends ActionItem {
#XmlAttribute
private String id;
#XmlElement(name = "ParentId")
private String parentID;
}
Main.class:
public class Main {
public static void main(String[] args) throws JAXBException, XMLStreamException {
final InputStream inputStream = Unmarshalling.class.getClassLoader().getResourceAsStream("action.xml");
final XMLStreamReader xmlStreamReader = XMLInputFactory.newInstance().createXMLStreamReader(inputStream);
final Unmarshaller unmarshaller = JAXBContext.newInstance(Action.class).createUnmarshaller();
final Action action = unmarshaller.unmarshal(xmlStreamReader, Action.class).getValue();
System.out.println(action.toString());
Marshaller marshaller = JAXBContext.newInstance(Action.class).createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FRAGMENT, Boolean.TRUE);
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
marshaller.marshal(action, System.out);
}
}
If you provided Employee XML then it produces the following result:
Action(id=5, type=Employee(id=10))
<Action id="5">
<Employee id="10">
<Name>John</Name>
</Employee>
</Action>
If you provide the Department XML then it produces the following result:
Action(id=5, type=Department(parentID=CDE))
<Action id="5">
<Department>
<Name>Economy Department</Name>
<ParentId>CDE</ParentId>
</Department>
</Action>
METHOD-2
Creating the interface and using it:
public interface ActionItem2 {
}
Action.class uses the created interface.
#XmlRootElement(name = "Action")
#Data
#XmlAccessorType(XmlAccessType.FIELD)
public class Action {
#XmlAttribute(name = "id")
protected String id;
#XmlElements({
#XmlElement(name = "Employee", type = Employee.class),
#XmlElement(name = "Department", type = Department .class),
})
private ActionItem2 type;
}
Employee.class which implements the created interface
#Data
#XmlAccessorType(XmlAccessType.NONE)
public class Employee implements ActionItem2 {
#XmlAttribute(name = "id")
private String id;
#XmlElement(name = "Name")
protected String name;
}
Department.class which implements the created interface
#Data
#XmlAccessorType(XmlAccessType.NONE)
public class Department implements ActionItem2 {
#XmlAttribute
private String id;
#XmlElement(name = "ParentId")
private String parentID;
#XmlElement(name = "Name")
protected String name;
}
Main.class(No changes)
public class Main {
public static void main(String[] args) throws JAXBException, XMLStreamException {
final InputStream inputStream = Unmarshalling.class.getClassLoader().getResourceAsStream("action.xml");
final XMLStreamReader xmlStreamReader = XMLInputFactory.newInstance().createXMLStreamReader(inputStream);
final Unmarshaller unmarshaller = JAXBContext.newInstance(Action.class).createUnmarshaller();
final Action action = unmarshaller.unmarshal(xmlStreamReader, Action.class).getValue();
System.out.println(action.toString());
Marshaller marshaller = JAXBContext.newInstance(Action.class).createMarshaller();
marshaller.setProperty(Marshaller.JAXB_FRAGMENT, Boolean.TRUE);
marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT, Boolean.TRUE);
marshaller.marshal(action, System.out);
}
}
The result would be the same.
Method - 3
If you don't want to modify your POJO then you can do something like this:
#XmlRootElement(name = "Action")
#Data
#XmlAccessorType(XmlAccessType.FIELD)
public class Action {
#XmlAttribute(name = "id")
protected String id;
#XmlElements({
#XmlElement(name = "Employee", type = Employee.class),
#XmlElement(name = "Department", type = Department .class),
})
private Object type;
}
Employee.class:
#Data
#XmlAccessorType(XmlAccessType.NONE)
public class Employee {
#XmlAttribute(name = "id")
private String id;
#XmlElement(name = "Name")
protected String name;
}
Department.class:
#Data
#XmlAccessorType(XmlAccessType.NONE)
public class Department {
#XmlAttribute
private String id;
#XmlElement(name = "ParentId")
private String parentID;
#XmlElement(name = "Name")
protected String name;
}
This will provide the same output.
I have an Abstract class used as MappedSuperclass like :
#MappedSuperclass
#IdClass(LogId.class)
public abstract class Log {
private LocalDateTime moment;
private String pid;
// attributes omitted
private String type;
private String message;
#Id
public LocalDateTime getMoment() { return moment; }
#Id
public String getPid() { return pid; }
// getters/setters omitted
}
My Log class provides to every entity the same structure with standard attributes type and message. Each entity represents a table in my database which share every attributes (#Id and // omitted ones). Columns type and message might have different names & types.
My first attempt was :
#Entity
#Table(name = "flow_catcher")
public class FlowCatcher extends Log {
#Override
#Column(name = "message_type")
public String getType() {
return super.getType();
}
#Override
#Column(name = "count")
#Convert(converter = StringToIntegerDbConverter.class)
public String getMessage() {
return super.getMessage();
}
}
Following this post I used #AttributeOverride like :
#Entity
#Table(name = "flow_catcher")
#AttributeOverride(name = "type", column = #Column(name = "message_type"))
#AttributeOverride(name = "message", column = #Column(name = "count"))
public class FlowCatcher extends Log {
}
But it seems impossible to use any converter to get data count as a String and not an Integer.
Here is my error log:
Unable to build Hibernate SessionFactory; nested exception is
org.hibernate.tool.schema.spi.SchemaManagementException:
Schema-validation: wrong column type encountered in column [count] in table [flow_catcher];
found [int (Types#INTEGER)], but expecting [varchar(255) (Types#VARCHAR)]
Is there any way to get my column count as a String and not an Integer ?
PS: Hibernate hbm2ddl.auto is set on validate and database scheme can't change.
EDIT 1: I found a working solution but it uses another (unused) column in my database other_string_column which doesn't sound clean to me :
#Entity
#Table(name = "flow_catcher")
#AttributeOverride(name = "type", column = #Column(name = "message_type"))
#AttributeOverride(name = "message", column = #Column(name = "other_string_column"))
public class FlowCatcher extends Log{
private Integer count;
#Override
public String getMessage() {
return this.count.toString();
}
public Integer getCount() { return count; }
public void setCount(Integer count) { this.count = count; }
}
You can go with generic
#MappedSuperclass
#IdClass(LogId.class)
public class Log<T extends Comparable> implements Serializable {
#Id
private LocalDateTime moment;
#Id
private String pid;
//additional required fields here
// Do NOT SPECIFY MAPPING
private T message;
}
#Entity
#Table(name = "flow_catcher")
#AttributeOverride(name = "type", column = #Column(name = "message_type"))
#AttributeOverride(name = "message", column = #Column(name = "count", columnDefinition = "BIGINT(15)"))
public class FlowCatcher extends Log<Integer> {
private static final long serialVersionUID = -3629698185247120860L;
}
#Entity
#Table(name = "flow_catcher_another_sample")
#AttributeOverride(name = "type", column = #Column(name = "message_type"))
#AttributeOverride(name = "message", column = #Column(name = "message", columnDefinition = "VARCHAR(20)"))
public class FlowCatcherString extends Log<String> {
private static final long serialVersionUID = -3629698185247120860L;
}
I am receiving following response and am trying to to parse it using JAXB but following code returns error below.
Exception in thread "main" org.springframework.http.converter.HttpMessageConversionException: Could not instantiate JAXBContext for class [class com.easytobook.EasytobookResponse]: 1 counts of IllegalAnnotationExceptions; nested exception is com.sun.xml.bind.v2.runtime.IllegalAnnotationsException: 1 counts of IllegalAnnotationExceptions
com.easytobook.Roomtype#totalTaxesAndFees has mutually exclusive annotations #javax.xml.bind.annotation.XmlAttribute and #javax.xml.bind.annotation.XmlElement
this problem is related to the following location:
at #javax.xml.bind.annotation.XmlAttribute(name=EUR, required=false, namespace=##default)
I know exception is related to totalTaxsesAndFees but I am not sure how to solve the issue.
EasytobookResponse response = restTemplate.postForObject(
url, easy, EasytobookResponse.class);
System.err.println("RESPONSE >>>>"
+ response.getResponse().getHotelInfo().get(0).getId());
#XmlRootElement(name = "EasytobookResponse")
#XmlAccessorType(XmlAccessType.FIELD)
public class EasytobookResponse {
#XmlAttribute(name = "target")
private String target;
#XmlAttribute(name = "username")
private String username;
#XmlElement(name = "Response")
private Response response;
getters and setters
#XmlRootElement(name = "Response")
#XmlAccessorType(XmlAccessType.FIELD)
public class Response {
#XmlElementWrapper(name="Hotelinfo")
#XmlElement(name="Hotel")
private List<Hotel> hotelInfo;
getters and setters
#XmlRootElement(name = "Hotel")
#XmlAccessorType(XmlAccessType.FIELD)
public class Hotel {
#XmlElement(name = "Id")
private int id;
#XmlElement(name = "FacilityGroups")
private FacilityGroups facilityGroups;
#XmlElement(name = "exact")
private int exact;
#XmlElementWrapper(name = "Roomtype")
#XmlElement(name = "Roomtype")
private List<Roomtype> roomType;
getters and setters
#XmlRootElement(name = "FacilityGroups")
#XmlAccessorType(XmlAccessType.FIELD)
public class FacilityGroups {
#XmlElement(name = "HandicapFacilities")
private int handicapFacilities;
#XmlElement(name = "HasInternet")
private int hasInternet;
#XmlElement(name = "HasParking")
private int hasParking;
#XmlElement(name = "PetsAllowed")
private int petsAllowed;
#XmlElement(name = "HasChildDiscount")
private int hasChildDiscount;
#XmlElement(name = "HasSwimmingPool")
private int hasSwimmingPool;
#XmlElement(name = "HasAirCon")
private int hasAirCon;
#XmlElement(name = "HasFitnessFacilities")
private int hasFitnessFacilities;
#XmlElement(name = "NonSmoking")
private int nonSmoking;
getters and setters
#XmlRootElement(name = "Roomtype")
#XmlAccessorType(XmlAccessType.FIELD)
public class Roomtype {
#XmlAttribute(name = "parentid")
private String parentid;
#XmlElement(name = "Roomid")
private long roomId;
#XmlElement(name = "Roomname")
private String roomName;
#XmlElement(name = "Capacity")
private int capacity;
#XmlElement(name = "Available")
private int available;
#XmlElement(name = "Totalrate")
private double totalRate;
#XmlAttribute(name="currency")
private String currency;
#XmlAttribute(name="EUR")
#XmlElement(name = "TotalTaxesAndFees")
private double totalTaxesAndFees;
#XmlElement(name = "TotalChargeable")
private double totalChargeable;
#XmlElement(name = "Reckratetotal")
private double reckRateTotal;
#XmlElement(name = "Breakfast")
private int breakfast;
#XmlElement(name = "Booklink")
private String bookLink;
#XmlElement(name = "Hoteldetailslink")
private String hotelDetailsLink;
#XmlElement(name = "Rtoken")
private String rToken;
#XmlElement(name = "Specialoffers")
private String specialOffers;
#XmlElement(name = "Bookingconditions")
private BookingConditions bookingConditions;
#XmlElement(name = "Rateinfo")
private RateInfo rateInfo;
getters and setters
#XmlRootElement(name = "Bookingconditions")
#XmlAccessorType(XmlAccessType.FIELD)
public class BookingConditions {
#XmlElement(name = "Bookable")
private int bookable;
#XmlElement(name = "Chargepoint")
private String chargePoint;
#XmlElement(name = "Requirements")
private Requirement requirement;
getters and setters
#XmlRootElement(name = "Requirements")
#XmlAccessorType(XmlAccessType.FIELD)
public class Requirement {
#XmlElement(name = "Capacity")
private int capacity;
#XmlElement(name = "Creditcardcvc")
private int creditCardCvc;
#XmlElement(name = "Billingaddress")
private int billingAddress;
getters and setters
#XmlRootElement(name = "Rateinfo")
#XmlAccessorType(XmlAccessType.FIELD)
public class RateInfo {
#XmlElement(name = "Underoccupancy")
private int underoccupancy;
#XmlElement(name = "Earlybooking")
private int earlyBooking;
#XmlElement(name = "Lastminutebooking")
private int lastMinuteBooking;
#XmlElement(name = "Nonrefundable")
private int nonRefundable;
#XmlElement(name = "Breakfastincluded")
private int breakfastIncluded;
getters and setters
Response
<?xml version="1.0" encoding="UTF-8"?>
<EasytobookResponse>
<Response target="test" username="project121">
<Hotelinfo>
<Hotel>
<Id>436924</Id>
<FacilityGroups>
<HandicapFacilities>0</HandicapFacilities>
<HasInternet>1</HasInternet>
<HasParking>1</HasParking>
<PetsAllowed>0</PetsAllowed>
<HasChildDiscount>0</HasChildDiscount>
<HasSwimmingPool>0</HasSwimmingPool>
<HasAirCon>1</HasAirCon>
<HasFitnessFacilities>0</HasFitnessFacilities>
<NonSmoking>1</NonSmoking>
</FacilityGroups>
<exact>436924</exact>
<Roomtype>
<Roomid parentid="2069840686">2069840686</Roomid>
<Roomname>Two Persons Standard + Breakfast</Roomname>
<Capacity>2</Capacity>
<Available>8</Available>
<Totalrate currency="AUD" EUR="1204.3398">1800</Totalrate>
<TotalTaxesAndFees currency="AUD" EUR="0">0
</TotalTaxesAndFees>
<TotalChargeable currency="AUD" EUR="1204.3398">1800
</TotalChargeable>
<Reckratetotal currency="AUD" EUR="1204.3398">1800
</Reckratetotal>
<Breakfast>1</Breakfast>
<Booklink>https://stage-site.easytobook.us/booking_screen.php?hotel_id=436924&exact=436924&city_id=23&arrival=20-11-2016&departure=29-11-2016¤cy=EUR&lang=en&room[2069840686]=1&persons=2&rooms=1&amu=280828207&utm_source=project121&utm_medium=affiliate&utm_term=Sydney&utm_content=etb5&utm_campaign=en&rtoken=1VSwnz7whjuxw-RGo5aP6cp-XmdDQSHC7twXmVrwPejOzYDFXdGY_bdbs9xbHuP8xU83qSmzJGz_vgQZHjeE5kVENJkuPBAtuKd6jTqIWCk,
</Booklink>
<Hoteldetailslink>http://stage-site.easytobook.us/hotel_proxy.php?hotel_id=436924&lang=en&arrival=20-11-2016&departure=29-11-2016¤cy=EUR&prs_arr%5B0%5D=2&amu=280828207&utm_source=project121&utm_medium=affiliate&utm_term=Sydney&utm_content=etb5&utm_campaign=en&rtoken=1VSwnz7whjuxw-RGo5aP6cp-XmdDQSHC7twXmVrwPejOzYDFXdGY_bdbs9xbHuP8xU83qSmzJGz_vgQZHjeE5kVENJkuPBAtuKd6jTqIWCk,
</Hoteldetailslink>
<Rtoken>1VSwnz7whjuxw-RGo5aP6cp-XmdDQSHC7twXmVrwPejOzYDFXdGY_bdbs9xbHuP8xU83qSmzJGz_vgQZHjeE5kVENJkuPBAtuKd6jTqIWCk,
</Rtoken>
<Specialoffers />
<Bookingconditions>
<Bookable>1</Bookable>
<Chargepoint>hotel</Chargepoint>
<Requirements>
<Capacity>1</Capacity>
<Creditcardcvc>1</Creditcardcvc>
<Billingaddress>1</Billingaddress>
</Requirements>
</Bookingconditions>
<Rateinfo>
<Underoccupancy>0</Underoccupancy>
<Earlybooking>0</Earlybooking>
<Lastminutebooking>0</Lastminutebooking>
<Nonrefundable>0</Nonrefundable>
<Breakfastincluded>1</Breakfastincluded>
</Rateinfo>
</Roomtype>
<Roomtype>
<Roomid parentid="1379794752">1379794752</Roomid>
<Roomname>Two Persons Superior + Breakfast</Roomname>
<Capacity>2</Capacity>
<Available>4</Available>
<Totalrate currency="AUD" EUR="1264.5568">1890</Totalrate>
<TotalTaxesAndFees currency="AUD" EUR="0">0
</TotalTaxesAndFees>
<TotalChargeable currency="AUD" EUR="1264.5568">1890
</TotalChargeable>
<Reckratetotal currency="AUD" EUR="1264.5568">1890
</Reckratetotal>
<Breakfast>1</Breakfast>
<Booklink>https://stage-site.easytobook.us/booking_screen.php?hotel_id=436924&exact=436924&city_id=23&arrival=20-11-2016&departure=29-11-2016¤cy=EUR&lang=en&room[1379794752]=1&persons=2&rooms=1&amu=280828207&utm_source=project121&utm_medium=affiliate&utm_term=Sydney&utm_content=etb5&utm_campaign=en&rtoken=ocGkvI7xuJJwz1BWWYNBztr7n-__tI8fVNfz3cZsrwRMGrtuHAEGziCH-0poK2ZoveEs-4Fz1_Y4U8pwE4KGKjJc4iwdSKM4ewIJwMU8omA,
</Booklink>
<Hoteldetailslink>http://stage-site.easytobook.us/hotel_proxy.php?hotel_id=436924&lang=en&arrival=20-11-2016&departure=29-11-2016¤cy=EUR&prs_arr%5B0%5D=2&amu=280828207&utm_source=project121&utm_medium=affiliate&utm_term=Sydney&utm_content=etb5&utm_campaign=en&rtoken=ocGkvI7xuJJwz1BWWYNBztr7n-__tI8fVNfz3cZsrwRMGrtuHAEGziCH-0poK2ZoveEs-4Fz1_Y4U8pwE4KGKjJc4iwdSKM4ewIJwMU8omA,
</Hoteldetailslink>
<Rtoken>ocGkvI7xuJJwz1BWWYNBztr7n-__tI8fVNfz3cZsrwRMGrtuHAEGziCH-0poK2ZoveEs-4Fz1_Y4U8pwE4KGKjJc4iwdSKM4ewIJwMU8omA,
</Rtoken>
<Specialoffers />
<Bookingconditions>
<Bookable>1</Bookable>
<Chargepoint>hotel</Chargepoint>
<Requirements>
<Capacity>1</Capacity>
<Creditcardcvc>1</Creditcardcvc>
<Billingaddress>1</Billingaddress>
</Requirements>
</Bookingconditions>
<Rateinfo>
<Underoccupancy>0</Underoccupancy>
<Earlybooking>0</Earlybooking>
<Lastminutebooking>0</Lastminutebooking>
<Nonrefundable>0</Nonrefundable>
<Breakfastincluded>1</Breakfastincluded>
</Rateinfo>
</Roomtype>
</Hotel>
.....
The error message says it all:
com.easytobook.Roomtype#totalTaxesAndFees has mutually exclusive annotations #javax.xml.bind.annotation.XmlAttribute and #javax.xml.bind.annotation.XmlElement
Your code has:
#XmlRootElement(name = "Roomtype")
#XmlAccessorType(XmlAccessType.FIELD)
public class Roomtype {
. . .
#XmlAttribute(name="EUR")
#XmlElement(name = "TotalTaxesAndFees")
private double totalTaxesAndFees;
That is not allowed.
Your problem is these XML elements:
<Roomtype>
<Roomid parentid="2069840686">2069840686</Roomid>
. . .
<Totalrate currency="AUD" EUR="1204.3398">1800</Totalrate>
<TotalTaxesAndFees currency="AUD" EUR="0">0</TotalTaxesAndFees>
<TotalChargeable currency="AUD" EUR="1204.3398">1800</TotalChargeable>
<Reckratetotal currency="AUD" EUR="1204.3398">1800</Reckratetotal>
For example, the following field annotation tells JAXB that parentid is an attribute of Roomtype, when you want it as an attribute of Roomid:
public class Roomtype {
#XmlAttribute(name = "parentid")
private String parentid;
Instead, in order to have an attribute on the <Roomid> element, you need a Roomid class (and you don't need the #XmlRootElement):
#XmlAccessorType(XmlAccessType.FIELD)
public class Roomid {
#XmlAttribute(name = "parentid")
private String parentid;
#XmlValue
private long roomId;
}
Your 4 total elements have the same structure, so they can share a single class:
#XmlAccessorType(XmlAccessType.FIELD)
public class Total {
#XmlAttribute(name = "currency")
private String currency;
#XmlAttribute(name = "EUR")
private double eur;
#XmlValue
private double total;
}
These two classes are then used like this:
#XmlAccessorType(XmlAccessType.FIELD)
public class Roomtype {
#XmlElement(name = "Roomid")
private Roomid roomid;
. . .
#XmlElement(name = "Totalrate")
private Total totalrate;
#XmlElement(name = "TotalTaxesAndFees")
private Total totalTaxesAndFees;
#XmlElement(name = "TotalChargeable")
private Total totalChargeable;
#XmlElement(name = "Reckratetotal")
private Total reckratetotal;
I'm sorry, the title is not very explicit... In my projet model, I have a Product entity that can be associated with other products, but I don't know how to annotate it. Currently, I have done that :
#XmlRootElement(name = "product")
#XmlType(propOrder = { "barCode", "productName", "price", "brand", "description", "reviews", "photos", "videos", "associated" })
#XmlAccessorType(XmlAccessType.FIELD)
public class Product {
#XmlAttribute(name = "id")
private Long productId;
private String barCode;
private String productName;
private Double price;
#XmlElementWrapper(name = "photos")
#XmlElement(name = "photo", type = String.class)
private List<String> photos;
#XmlElementWrapper(name = "videos")
#XmlElement(name = "video", type = String.class)
private List<String> videos;
private String brand;
private String description;
#XmlElementWrapper(name = "reviews")
#XmlElement(name = "review", type = Review.class)
private List<Review> reviews;
#XmlElementWrapper(name = "associated")
#XmlElement(name = "product", type = Product.class)
private List<Product> associated;
// with constructor, getters and setters not annotated
}
Currently, this mapping is not working, because of cyclic references. I would like to have something like :
<product id="1">
<barCode>123456789</barCode>
<productName>Product 1</productName>
<price>100.0</price>
<brand>Brand 1</brand>
<description>Description 1</description>
<reviews/>
<photos/>
<videos/>
<associated>
<product id="2">
<barCode>987654321</barCode>
<productName>Product 2</productName>
<price>500.0</price>
<brand>Brand 2</brand>
<description>Description 2</description>
</product>
</associated>
</product>
I mean not have in the mapping photos, videos, reviews and associated, is it possible?
I hope I was clear enought, if wasn't just ask, I'll explain more in detail !
If you want to exclude mapped fields, use #XmlTransient (good for handling cyclic references)