I'm trying to implement a unidirectional many to many relationship between entities with spring+JPA.
After a few tries changing hibernate versions I don't know whats the cause
Caused by: org.springframework.orm.jpa.JpaSystemException: Error accessing field [private java.lang.Integer com.uca.refactor2.model.Achievement.id] by reflection for persistent property [com.uca.refactor2.model.Achievement#id] : 1; nested exception is org.hibernate.property.access.spi.PropertyAccessException: Error accessing field [private java.lang.Integer com.uca.refactor2.model.Achievement.id] by reflection for persistent property [com.uca.refactor2.model.Achievement#id] : 1
User.java
#Entity
#Table(name="USER")
public class User implements Serializable {
private static final long serialVersionUID = 4402583037980335445L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String firstName;
private String lastName;
#Column(unique = true)
private String username;
private String password;
#Enumerated(EnumType.STRING)
private UserType userType;
#OneToMany(cascade=CascadeType.ALL, mappedBy="joinedUserAchievementId.user")
private List<JoinedUserAchievement> joinedUserAchievementList = new ArrayList<JoinedUserAchievement>();
public User() {}
public User(Integer id) {
this.id = id;
}
public User(String username, String firstName, String lastName,
String password, UserType userType) {
this.username = username;
this.firstName = firstName;
this.lastName = lastName;
this.password = password;
this.userType = userType;
}
public List<JoinedUserAchievement> getAllAchievement() {
return joinedUserAchievementList;
}
public void addAchievement(Achievement achievement) {
// Notice a JoinedUserAchievement object
Date dateOfAcquisition = new Date();
JoinedUserAchievement joinedUserAchievement = new JoinedUserAchievement(new JoinedUserAchievement.JoinedUserAchievementId(this, achievement),dateOfAcquisition );
joinedUserAchievement.setAchievementId(achievement.getId());
joinedUserAchievementList.add(joinedUserAchievement);
}
//set and gets
JoinedUserAchievement.java
#Entity
#Table(name="USER_ACHIEVEMENT")
public class JoinedUserAchievement {
public JoinedUserAchievement() {}
public JoinedUserAchievement(JoinedUserAchievementId joinedUserAchievementId, Date dateOfAcquisition) {
this.joinedUserAchievementId = joinedUserAchievementId;
this.dateOfAcquisition = dateOfAcquisition;
}
#ManyToOne(targetEntity = Achievement.class)
#JoinColumn(name="id", insertable=false, updatable=false)
private Integer achievementId;
private Date dateOfAcquisition;
public String getDate() {
DateFormat dateFormat = new SimpleDateFormat("dd/MM/yyyy HH:mm:ss");
Date date = dateOfAcquisition;
return dateFormat.format(date);
}
public Integer getAchievementId() {
return achievementId;
}
public void setAchievementId(Integer achievementId) {
this.achievementId = achievementId;
}
#EmbeddedId
private JoinedUserAchievementId joinedUserAchievementId;
// required because JoinedUserAchievments contains composite id
#Embeddable
public static class JoinedUserAchievementId implements Serializable {
/**
*
*/
private static final long serialVersionUID = -9180674903145773104L;
#ManyToOne
#JoinColumn(name="USER_ID")
private User user;
#ManyToOne
#JoinColumn(name="ACHIEVEMENT_ID")
private Achievement achievement;
// required no arg constructor
public JoinedUserAchievementId() {}
public JoinedUserAchievementId(User user, Achievement achievement) {
this.user = user;
this.achievement = achievement;
}
public JoinedUserAchievementId(Integer userId, Integer achievementId) {
this(new User(userId), new Achievement(achievementId));
}
public User getUser() {
return user;
}
public Achievement getAchievement() {
return achievement;
}
public void setUser(User user) {
this.user = user;
}
public void setAchievement(Achievement achievement) {
this.achievement = achievement;
}
#Override
public boolean equals(Object instance) {
if (instance == null)
return false;
if (!(instance instanceof JoinedUserAchievementId))
return false;
final JoinedUserAchievementId other = (JoinedUserAchievementId) instance;
if (!(user.getId().equals(other.getUser().getId())))
return false;
if (!(achievement.getId().equals(other.getAchievement().getId())))
return false;
return true;
}
#Override
public int hashCode() {
int hash = 7;
hash = 47 * hash + (this.user != null ? this.user.hashCode() : 0);
hash = 47 * hash + (this.achievement != null ? this.achievement.hashCode() : 0);
return hash;
}
}
}
Achievement.java
#Entity
#Table(name="ACHIEVEMENT")
public class Achievement implements Serializable{
private static final long serialVersionUID = 7747630789725422177L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String name;
private Integer points;
public Achievement() {
}
public Achievement(String name, Integer points) {
this.name = name;
this.points = points;
}
public Achievement(Integer id) {
this.id = id;
}
//set and gets
I've also tried to make this relationship bidirectional and it didn't work, so I may be missing something
Also before this I had achievement objects instead of achievementId on joinedUserAchievement, it worked but I think its not what I need, I don't need to get every achievement object always, with only the id is fine.
From the docs:
Relationship mappings defined within an embedded id class are not supported
You should put the ids only in JoinedUserAchievementId, and put User and Achievement associations in JoinedUserAchievement directly like so:
public class JoinedUserAchievementId {
private Long userId;
private Long achievementId;
...
}
public class JoinedUserAchievement {
#EmbeddedId
private JoinedUserAchievementId joinedUserAchievementId;
#ManyToOne
#MapsId("userId")
#JoinColumn(name = "USER_ID")
private User user;
#ManyToOne(optional = false, fetch = LAZY)
#MapsId("achievementId")
#JoinColumn(name = "ACHIEVEMENT_ID")
private Achievement achievement;
//if you absolutely need to map the achievement_id column here as well
//note that it will already be mapped to joinedUserAchievementId.achievementId
#Column(name = "ACHIEVEMENT_ID", insertable=false, updatable=false)
private Long achievementId;
...
}
Remember to update the User.joinedUserAchievementList mapping to mappedBy="user".
Related
I have 3 tables. Hospitals and doctors. The 3rd table is a junction table of both that contains id,ids of 2 other tables as foreign keys and few other columns. When trying to put record to a junction table I got an error that one of foreign keys have to be set with insertable=false. However when I set it like this then I get that the value can't be null (since my database requires that field).I'm stuck and can't go any further with those 2 errors.
If I manage to avoid those 2 errors then I get an erorr that there is an unknown column in the field list.
Doctors entity:
#Entity
#Table(name = "doctors")
public class Doctors implements Serializable {
private Integer id;
private String name;
private String surname;
private String title;
private String licenseNumber;
private String phone;
private String email;
private String nationality;
private String speciality;
private LocalDate dateOfBirth;
private Boolean isATeacher;
private List<HospitalDoctors> hospitalDoctors = new LinkedList<>();
//consturctors
#Id
#GenericGenerator(name = "generator", strategy = "increment")
#GeneratedValue(generator = "generator")
#Column(name = "Idd", nullable = false)
public Integer getId() {
return this.id;
}
public void setId(Integer id) {
this.id = id;
}
//setters and getters for rest of the fields with #column annotations on getters
#OneToMany(fetch = FetchType.LAZY, mappedBy = "pk.doctor", cascade = {CascadeType.PERSIST, CascadeType.MERGE})
#Cascade({org.hibernate.annotations.CascadeType.SAVE_UPDATE, org.hibernate.annotations.CascadeType.DELETE})
public List<HospitalDoctors> getHospitalDoctors() {
return hospitalDoctors;
}
public void setHospitalDoctors(List<HospitalDoctors> hospitalDoctors) {
this.hospitalDoctors = hospitalDoctors;
}
Hospitals entity:
#Entity
#Table(name = "hospitals")
public class Hospitals implements Serializable {
private Integer id;
private String name;
private String country;
private String town;
private String street;
private String postalCode;
private String phoneNumber;
private String faxNumber;
private Integer numberOfAmbulances;
private Boolean helicopterAccess;
private Boolean teachingHospital;
private List<HospitalDoctors> hospitalDoctors = new LinkedList<>();
//constructors
#Id
#GenericGenerator(name = "generator", strategy = "increment")
#GeneratedValue(generator = "generator")
#Column(name = "Idh", nullable = false)
public Integer getId() {
return this.id;
}
public void setId(Integer id) {
this.id = id;
}
//getters setters with #column annotations over getters
#OneToMany(fetch = FetchType.LAZY, mappedBy = "pk.hospital", cascade = {CascadeType.PERSIST, CascadeType.MERGE})
#Cascade({org.hibernate.annotations.CascadeType.SAVE_UPDATE, org.hibernate.annotations.CascadeType.DELETE})
public List<HospitalDoctors> getHospitalDoctors() {
return this.hospitalDoctors;
}
public void setHospitalDoctors(List<HospitalDoctors> hospitalDoctors) {
this.hospitalDoctors = hospitalDoctors;
}
Junction table entity:
#Entity
#Table(name = "hospitaldoctors")
#AssociationOverrides({
#AssociationOverride(name = "pk.hospital",
joinColumns = #JoinColumn(name = "Idh")),
#AssociationOverride(name = "pk.doctor",
joinColumns = #JoinColumn(name = "Idd"))
})
public class HospitalDoctors implements Serializable {
private Integer id;
private Integer idH;
private Integer idD;
private HospitalDoctorsId pk = new HospitalDoctorsId();
private LocalDate contractStartDate;
private LocalDate contractEndDate;
private String position;
private Boolean supervisor;
private Boolean partTime;
//constructors
#Column(name ="Idhos")
public Integer getIdH() {
return this.idH;
}
public void setIdH(Integer idH) {
this.idH = idH;
}
#Column(name ="Iddoc")
public Integer getIdD() {
return this.idD;
}
public void setIdD(Integer idD) {
this.idD = idD;
}
#EmbeddedId
public HospitalDoctorsId getPk() {
return pk;
}
public void setPk(HospitalDoctorsId pk) {
this.pk = pk;
}
#Transient
public Hospitals getHospital(){
return getPk().getHospital();
}
public void setHospital(Hospitals hospital){
getPk().setHospital(hospital);
}
#Transient
public Doctors getDoctor(){
return getPk().getDoctor();
}
public void setDoctor(Doctors doctor){
getPk().setDoctor(doctor);
}
//rest of the setters getters with #Column
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
HospitalDoctors that = (HospitalDoctors) o;
if(getPk() != null?!getPk().equals(that.getPk()) : that.getPk() != null) return false;
return true;
}
#Override
public int hashCode() {
return (getPk() != null? getPk().hashCode() : 0);
}
Junction table Id:
#Embeddable
public class HospitalDoctorsId implements Serializable {
private Hospitals hospital;
private Doctors doctor;
#ManyToOne
public Hospitals getHospital() {
return hospital;
}
public void setHospital(Hospitals hospital) {
this.hospital = hospital;
}
#ManyToOne
public Doctors getDoctor() {
return doctor;
}
public void setDoctor(Doctors doctor) {
this.doctor = doctor;
}
#Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
HospitalDoctorsId that = (HospitalDoctorsId) o;
if(hospital != null?!hospital.equals(that.hospital) : that.hospital != null) return false;
if(doctor != null?!doctor.equals(that.doctor) : that.doctor != null) return false;
return true;
}
#Override
public int hashCode() {
int result;
result = (hospital != null? hospital.hashCode() : 0);
result = 31* result + (doctor != null? doctor.hashCode() : 0);
return result;
}
}
I expected to be able to add records to junction table in data base in form fields I have foreign keys for hospital and doctors id to put in as well as other fields. Unfortunately I get either error that say to put foreign keys columns idD and idH as insertable, updatable false which leads to null value being passed which gives another error. When I solve those errors I get the error:
java.sql.SQLSyntaxErrorException: Unknown column 'hospitaldo0_.Idd' in 'field list'when trying to display records nad unknown column Idd when trying to add record (displaying works when Im getting insertable error or null value error. adding never works)
If I remember correctly, you need to have a single #ManyToMany relation rather than two #OneToMany relations.
I have 2 classes, TransportOrder and LardiSendedOrder. It's bounded by field innerId, and I just want list all records from LardiSendedOrder table, but got this error.
Error accessing field [private java.lang.Integer com.example.model.LardiSendedOrder.innerId] by reflection for persistent property [com.example.model.LardiSendedOrder#innerId] : 1;
class Transport Order
#Entity
class TransportOrder {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Integer id;
private String url;
private String source;
private String transport;
private Date start_date;
private Date end_date;
private String start_address;
private String end_address;
private ArrayList<String> phones =new ArrayList<>()
private Integer distance;
private String content;
private String weight;
private String size;
private Boolean fromVendor;
private ArrayList<PaymentType> payment_type = new ArrayList<PaymentType>();
private Double payment;
private String payment_by;
private ArrayList<PaymentEvent> payment_event = new ArrayList<PaymentEvent>();
private Date add_date;
#NotNull
#Column(unique=true)
private Integer hashCode;
LardiSendedOrder getLardiSendedOrder() {
return lardiSendedOrder
}
void setLardiSendedOrder(LardiSendedOrder lardiSendedOrder) {
this.lardiSendedOrder = lardiSendedOrder
}
#OneToOne
#JoinColumn(
/* referencedColumnName = "innerId"*/
referencedColumnName = "innerId"
)
private LardiSendedOrder lardiSendedOrder;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
//another getters and setters omitted
}
class LardiSendedOrder
#Entity
class LardiSendedOrder {
#Id
#GeneratedValue(strategy= GenerationType.AUTO)
private Integer id;
private Integer innerId;
private Integer outerId;
private Date publish_date;
Integer getUserId() {
return userId
}
void setUserId(Integer userId) {
this.userId = userId
}
private Integer userId;
TransportOrder getTransportOrder() {
return transportOrder
}
void setTransportOrder(TransportOrder transportOrder) {
this.transportOrder = transportOrder
}
#OneToOne(
cascade = CascadeType.ALL,
fetch = FetchType.LAZY,
mappedBy = "lardiSendedOrder")
private TransportOrder transportOrder;
Integer getInnerId() {
return innerId
}
void setInnerId(Integer innerId) {
this.innerId = innerId
}
Integer getOuterId() {
return outerId
}
void setOuterId(Integer outerId) {
this.outerId = outerId
}
String getPublish_date() {
return publish_date.format("dd.MM.yyyy HH:mm:ss");;
}
void setPublish_date(Date publish_date) {
this.publish_date = publish_date
}
}
And i just call
ArrayList<LardiSendedOrder> orders = (ArrayList<LardiSendedOrder>) lardiSendedOrderRepository.findAll();
Im usig Spring mvc and Hibernate. When I select from 2 tables, I received an exception following as:
My Bean (Cars and Map):
Cars class:
#Entity
#Table(name="Cars")
public class Car implements Serializable {
private static final long serialVersionUID = 5924361831551833717L;
#Id
#Column(name = "id")
#GeneratedValue(strategy=GenerationType.AUTO)
private Integer carId;
#Column(name = "name")
private String name;
#ManyToOne
#JoinColumn(name="map_id")
private Map mapId;
public Integer getCarId() {
return this.carId;
}
public void setCarId(Integer carId) {
this.carId = carId;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Map getMapId() {
return this.mapId;
}
public void setMapId(Map mapId) {
this.mapId = mapId;
}
}
Map class:
#Entity
#Table(name="Map")
public class Map implements Serializable {
private static final long serialVersionUID = -5527566248002296042L;
#Id
#Column(name = "id")
#GeneratedValue(strategy=GenerationType.AUTO)
private Integer mapId;
#Column(name = "address")
private String address;
public Integer getMapId() {
return mapId;
}
public void setMapId(Integer mapId) {
this.mapId = mapId;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
}
SQL (select from 2 tables):
SELECT CAR.ID AS carId,
CAR.NAME AS name,
MAP.ID AS mapId
FROM CARS CAR,
MAP MAP
WHERE CAR.MAP_ID = MAP.ID
Log message:
BasicPropertyAccessor - HHH000123: IllegalArgumentException in class: com.totoroads.web.model.Car, setter method of property: mapId
BasicPropertyAccessor - HHH000091: Expected type: com.totoroads.web.model.Map, actual value: java.lang.Integer
CarRepositoryImpl - error at CarRepositoryImpl.getAllCars: IllegalArgumentException occurred while calling setter for property [com.tct.web.model.Car.mapId (expected type = com.tct.web.model.Map)]; target = [com.tct.web.model.Car#23743c55], property value = [13] setter of com.tct.web.model.Car.mapId
How to fix this error, thank so much !
#Entity
#Table(name="Map")
public class Map implements Serializable {
private static final long serialVersionUID = -5527566248002296042L;
#Id
#Column(name = "id")
#GeneratedValue(strategy=GenerationType.AUTO)
private Integer mapId;
#OneToMany(mappedBy = "mapId", cascade = CascadeType.ALL)
private List<Car> cars;
#Column(name = "address")
private String address;
public Integer getMapId() {
return mapId;
}
public void setMapId(Integer mapId) {
this.mapId = mapId;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public List<Car> getCars() {
return cars;
}
public void setCars(List<Car> cars) {
this.cars= cars;
}
}
use above map class
I'm using Jersey + spring + hibernate4.17 to develop api system; The problem is if the cleaFields is called twice at same time, the 2nd call will throw an exception as below,
org.hibernate.StaleStateException: Batch update returned unexpected row count from update [0]; actual row count: 0; expected: 1
at org.hibernate.jdbc.Expectations$BasicExpectation.checkBatched(Expectations.java:81)
at org.hibernate.jdbc.Expectations$BasicExpectation.verifyOutcome(Expectations.java:73)
at org.hibernate.engine.jdbc.batch.internal.BatchingBatch.checkRowCounts(BatchingBatch.java:133)
at org.hibernate.engine.jdbc.batch.internal.BatchingBatch.performExecution(BatchingBatch.java:110)
at org.hibernate.engine.jdbc.batch.internal.BatchingBatch.doExecuteBatch(BatchingBatch.java:101)
at org.hibernate.engine.jdbc.batch.internal.AbstractBatchImpl.execute(AbstractBatchImpl.java:149)
at org.hibernate.engine.jdbc.internal.JdbcCoordinatorImpl.executeBatch(JdbcCoordinatorImpl.java:162)
at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:357)
at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:280)
at org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:326)
at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:52)
at org.hibernate.internal.SessionImpl.flush(SessionImpl.java:1213)
The clearFields method in the Controller,
#Transactional(isolation=Isolation.REPEATABLE_READ)
public void clearFields(Integer userId) {
User user = this.userDao.get(userId);
user.getFields().clear();
userDao.flush(); //call the current session.flush(); this line can throw exception.
}
User Entity class
#Entity
#Table(name="users")
#NamedQuery(name="User.findAll", query="SELECT u FROM User u")
public class User implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
#Column(name="id", unique = true, nullable = false)
private int userId;
#OneToMany(mappedBy = "user", cascade = { CascadeType.ALL }, targetEntity = UserProfile.class, fetch = FetchType.LAZY, orphanRemoval=true)
#OrderBy("id")
private List<UserProfile> fields = new ArrayList<UserProfile>();
public User() {
}
public int getUserId() {
return userId;
}
public void setUserId(int userId) {
this.userId = userId;
}
public List<UserProfile> getFields() {
return fields;
}
public void setFields(List<UserProfile> fields) {
this.fields = fields;
}
}
UserProfile class,
#Entity
#Table(name="user_profiles")
public class UserProfile implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy=GenerationType.IDENTITY)
private Integer id;
#Column(name="field_name")
private String fieldName;
#ManyToOne(targetEntity = User.class, fetch = FetchType.LAZY)
#JoinColumn(name="user_id")
private User user;
private String value;
public UserProfile() {
}
public Integer getId() {
return this.id;
}
public void setId(Integer id) {
this.id = id;
}
public String getFieldName() {
return this.fieldName;
}
public void setFieldName(String fieldName) {
this.fieldName = fieldName;
}
public String getValue() {
return this.value;
}
public void setValue(String value) {
this.value = value;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
}
I did some research, the root cause is if the 2nd calling get some fields, and before delete them, the 1st calling already delete all fields from database.
In another word, the 2nd calling try to delete some records which already were deleted by others.
How can I solve the problem?
I have two DTO objects say A and B which are having getters and setters and are used to take data from the database. The problem is when I am calling A, B gets called and B again points itself to A and a cycle is created.
I cannot ignore/hide the method which is creating the cycle. I need to take the whole data of A and B.
Is there any way to achieve it ?
Please help
This is my code which is causing the problem. This is application DTO which is calling environment DTO
#OneToMany(mappedBy="application", fetch=FetchType.LAZY
,cascade=CascadeType.ALL
)
public Set<EnvironmentDTO> getEnvironment() {
return environment;
}
public void setEnvironment(Set<EnvironmentDTO> environment) {
this.environment = environment;
}
And this is environment DTO which is calling the application DTO
#ManyToOne(targetEntity=ApplicationDTO.class )
#JoinColumn(name="fk_application_Id")
public ApplicationDTO getApplication() {
return application;
}
public void setApplication(ApplicationDTO application) {
this.application = application;
}
Here cycle is getting created
This is my rest call which will give result in XML format and I think while creating XML cycle is getting created
#GET
#Path("/get")
#Produces({MediaType.APPLICATION_XML})
public List<ApplicationDTO> getAllApplications(){
List<ApplicationDTO> allApplication = applicationService.getAllApplication();
return allApplication;
}
This is the Application DTO class
#Entity
#Table(name="application")
#org.hibernate.annotations.GenericGenerator(
name ="test-increment-strategy",strategy = "increment")
#XmlRootElement
public class ApplicationDTO implements Serializable {
#XmlAttribute
public Long appTypeId;
private static final long serialVersionUID = -8027722210927935073L;
private Long applicationId;
private String applicationName;
private ApplicationTypeDTO applicationType;
private String applicationDescription;
private Integer owner;
private Integer createdBy;
private Integer assignedTo;
private Date createTime;
private Date modifiedTime;
private Set<EnvironmentDTO> environment;
#Id
#GeneratedValue(generator = "test-increment-strategy")
#Column(name = "applicationId")
public Long getApplicationId() {
return applicationId;
}
private void setApplicationId(Long applicationId) {
this.applicationId = applicationId;
}
#Column(name = "applicationName")
public String getApplicationName() {
return applicationName;
}
public void setApplicationName(String applicationName) {
this.applicationName = applicationName;
}
#ManyToOne(targetEntity=ApplicationTypeDTO.class
,fetch = FetchType.LAZY
)
#JoinColumn(name="applicationType")
public ApplicationTypeDTO getApplicationType() {
return applicationType;
}
public void setApplicationType(ApplicationTypeDTO applicationType) {
this.applicationType = applicationType;
}
#Column(name = "description")
public String getApplicationDescription() {
return applicationDescription;
}
public void setApplicationDescription(String applicationDescription) {
this.applicationDescription = applicationDescription;
}
#Column(name = "owner")
public Integer getOwner() {
return owner;
}
public void setOwner(Integer owner) {
this.owner = owner;
}
#Column(name = "createdBy")
public Integer getCreatedBy() {
return createdBy;
}
public void setCreatedBy(Integer createdBy) {
this.createdBy = createdBy;
}
#Column(name = "assignedTo")
public Integer getAssignedTo() {
return assignedTo;
}
public void setAssignedTo(Integer assignedTo) {
this.assignedTo = assignedTo;
}
#Column(name = "createTime")
public Date getCreateTime() {
return createTime;
}
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
#Column(name = "modifiedTime")
public Date getModifiedTime() {
return modifiedTime;
}
public void setModifiedTime(Date modifiedTime) {
this.modifiedTime = modifiedTime;
}
#OneToMany(mappedBy="application", fetch=FetchType.LAZY
,cascade=CascadeType.ALL
)
public Set<EnvironmentDTO> getEnvironment() {
return environment;
}
public void setEnvironment(Set<EnvironmentDTO> environment) {
this.environment = environment;
}
This is the Environment DTO class
#Entity
#Table(name="environment")
#org.hibernate.annotations.GenericGenerator(
name = "test-increment-strategy",
strategy = "increment")
#XmlRootElement
public class EnvironmentDTO implements Serializable {
#XmlAttribute
public Long envTypeId;
#XmlAttribute
public Long appId;
private static final long serialVersionUID = -2756426996796369998L;
private Long environmentId;
private String environmentName;
private EnvironmentTypeDTO environmentType;
private Integer owner;
private Date createTime;
private Set<InstanceDTO> instances;
private ApplicationDTO application;
#Id
#GeneratedValue(generator = "test-increment-strategy")
#Column(name = "envId")
public Long getEnvironmentId() {
return environmentId;
}
private void setEnvironmentId(Long environmentId) {
this.environmentId = environmentId;
}
#Column(name = "envName")
public String getEnvironmentName() {
return environmentName;
}
public void setEnvironmentName(String environmentName) {
this.environmentName = environmentName;
}
#ManyToOne(targetEntity=EnvironmentTypeDTO.class)
#JoinColumn(name = "envType")
public EnvironmentTypeDTO getEnvironmentType() {
return environmentType;
}
public void setEnvironmentType(EnvironmentTypeDTO environmentType) {
this.environmentType = environmentType;
}
#Column(name = "owner")
public Integer getOwner() {
return owner;
}
public void setOwner(Integer owner) {
this.owner = owner;
}
#Temporal(TemporalType.DATE)
#Column(name = "createTime")
public Date getCreateTime()
{
return createTime;
}
public void setCreateTime(Date createTime) {
this.createTime = createTime;
}
#OneToMany(mappedBy="environment", cascade=CascadeType.ALL, fetch = FetchType.EAGER)
public Set<InstanceDTO> getInstances() {
return instances;
}
public void setInstances(Set<InstanceDTO> instances) {
this.instances = instances;
}
#ManyToOne(targetEntity=ApplicationDTO.class )
#JoinColumn(name="fk_application_Id")
//#XmlTransient
public ApplicationDTO getApplication() {
return application;
}
public void setApplication(ApplicationDTO application) {
this.application = application;
}
Your object graph is cyclic. There is nothing intrinsically wrong with that, and it is a natural consequence of using JPA.
Your problem is not that your object graph is cyclic, but that you are encoding it in a format which cannot handle cycles. This isn't a Hibernate question, it's a JAXB question.
My suggestion would be to stop JAXB from attempting to marshal the application property of the EnvironmentDTO class. Without that property the cyclic graph becomes a tree. You can do this by annotating that property with #XmlTransient.
(confession: i learned about this annotation by reading a blog post by Mr Doughan, which i came across after reading his answer to this question!)
Note: I'm the EclipseLink JAXB (MOXy) lead and a member of the JAXB (JSR-222) expert group.
MOXy offers the #XmlInverseReference extension to handle this use case. Below is an example of how to apply this mapping on two entities with a bidirectional relationship.
Customer
import javax.persistence.*;
#Entity
public class Customer {
#Id
private long id;
#OneToOne(mappedBy="customer", cascade={CascadeType.ALL})
private Address address;
}
Address
import javax.persistence.*;
import org.eclipse.persistence.oxm.annotations.*;
#Entity
public class Address implements Serializable {
#Id
private long id;
#OneToOne
#JoinColumn(name="ID")
#MapsId
#XmlInverseReference(mappedBy="address")
private Customer customer;
}
For More Information
http://blog.bdoughan.com/2010/07/jpa-entities-to-xml-bidirectional.html
http://blog.bdoughan.com/2013/03/moxys-xmlinversereference-is-now-truly.html
My advice is not exposing your JPA entity class to your webservices. You can create different POJO class and convert your JPA entity to the POJO. For example:
this is your JPA entity
import javax.persistence.*;
#Entity
public class Customer {
#Id
private long id;
#OneToOne(mappedBy="customer", cascade={CascadeType.ALL})
private Address address;
}
you should use this class for your webservices:
public class CustomerModel{
private long id;
//you can call different WS to get the Address class, or combine to this model
public void setFromJpa(Customer customer){
this.id = customer.id;
}
}