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)
Related
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.
In my Spring Boot app, I use Hibernate and applied the necessary relations to the following entities properly.
#Entity
public class Recipe {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(nullable=false, length=50)
private String title;
#OneToMany(mappedBy = "recipe", cascade = CascadeType.ALL)
private List<RecipeIngredient> recipeIngredients = new ArrayList<>();
}
#Entity
public class RecipeIngredient {
#EmbeddedId
private RecipeIngredientId recipeIngredientId = new RecipeIngredientId();
#ManyToOne(optional = true, fetch = FetchType.LAZY)
#MapsId("recipeId")
#JoinColumn(name = "recipe_id", referencedColumnName = "id")
private Recipe recipe;
#ManyToOne(optional = true, fetch = FetchType.LAZY)
#MapsId("ingredientId")
#JoinColumn(name = "ingredient_id", referencedColumnName = "id")
private Ingredient ingredient;
}
#Entity
public class Ingredient
{
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(unique=true, nullable=false, length=50)
#EqualsAndHashCode.Include
private String name;
#OneToMany(mappedBy = "ingredient", cascade = CascadeType.ALL)
private Set<RecipeIngredient> recipeIngredients = new HashSet<>();
}
Now I am trying to retrieve data by merging related entities. For example, when retrieving a Recipe, I also need to retrieve all Ingredients belonging to this Recipe.
As far as I know, I can use Projection and maybe it is better to only use Hibernate features and retrieve related table data via Java Stream. I have no idea how should I retrieve data via Hibernate.
Suppose that I just need an Optional<Recipe> that has List<Ingredient>. Then, I probably need a DTO class something like that:
#Data
public class ResponseDTO {
private Long id;
private String title;
List<RecipeIngredient> ingredients;
// getter, setter, constructor
}
So, how should I populate this DTO with the requested Recipe and corresponding Ingredient data (getting Ingredient names besides id values) using Java Stream?
Or if you suggest Projection way, I tried it but the data is multiplied by the ingredient count belonging to the searched recipe.
Update:
#Getter
#Setter
#NoArgsConstructor
public class ResponseDTO {
private Long id;
private String title;
List<IngredientDTO> ingredientDTOList;
public ResponseDTO(Recipe recipe) {
this.id = recipe.getId();
this.title = recipe.getTitle();
this.ingredientDTOList = recipe.getRecipeIngredients().stream()
.map(ri -> new IngredientDTO(ri.getIngredient().getName()))
.toList();
}
}
#Getter
#Setter
public class IngredientDTO {
private Long id;
private String name;
public IngredientDTO(String name) {
this.name = name;
}
}
First, in the ResponseDTO you will need you change the type of ingredients from List<RecipeIngredient> to List<Ingredient>.
To manually perform the mapping, you should use (to map from a suppose Recipe recipe to a RespondeDTO response):
ResponseDTO recipeToResponseDTO(Recipe recipe) {
ResponseDTO response = new ResponseDTO();
response.setId(recipe.getId());
response.setTitle(recipe.getTitle());
response.setIngredients(recipe.recipeIngredients.stream()
.map(RecipeIngredient::getIngredient()
.collect(Collectors.toList());
return response;
}
On the other hand, to model a n-n relation, I encourage you to use the approach proposed by E-Riz in the comment.
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 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 have the following embeddable classes.
Email:
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "Email")
#Embeddable
public class Email {
#XmlElement(required = true, nillable = true, name = "etype")
private String type;
private String address;
private String source;
// getters and setters
}
Address:
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "MyAddress")
#Embeddable
public class MyAddress {
#XmlElement(required = true, nillable = true, name = "atype")
private String type;
private String zip;
// getters and setters
}
Entity that embeds both of the above.
#Entity
#Table(name = "PERSON")
public class MyPerson {
#Embedded
#AttributeOverrides({
#AttributeOverride(name = "address", column = #Column(name = "E_ADDR")),
#AttributeOverride(name = "source", column = #Column(name = "E_SRC")) })
private Email email;
#Embedded
#AttributeOverrides({
#AttributeOverride(name = "zip", column = #Column(name = "ZIP")),
private MyAddress address;
}
There is a type field in both of the Embeds. But that field is not mapped to any Database field. But I need to override it. Because hibernate throws error when running. (Compiles fine).
Is there a way to override type or give a different name to the embedded and non-database-mapped field?
Note: I am looking for solution with the field name intact. Because I cannot simply change the name.
This would also answer my another question, embedding the same Embeddable again overriding all attributes. For instance, I want to include Home Address, Business Address, etc with same MyAddress embed.
All your fields which are not mapped to the database should be annotated with #Transient. In this case Hibernate will not try to map the field type and will not complain for a duplicate name.