JAXB null/empty field - java

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

Order Attribute in JacksonXmlProperty

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.

How to marshall XML with dynamic element using JAXB2

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.

AttributeOverride MappedSuperClass attribute with a different type

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;
}

JAXB returns mutually exculasive annotations exception

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&currency=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&currency=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&currency=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&currency=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;

Jaxb association of the same class

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)

Categories