One-to-One Relationship with Hibernate-JPA - java

I am having the following error when committing an Entity. According to error I have to assign an id for the Entity but I am expecting it has to be handled by JPA itself.
Exception in thread "main" javax.persistence.PersistenceException: org.hibernate.id.IdentifierGenerationException: ids for this class must be manually assigned before calling save(): alarm.ServiceAlarmConfEntity
at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1214)
at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1147)
at org.hibernate.ejb.AbstractEntityManagerImpl.convert(AbstractEntityManagerImpl.java:1153)
at org.hibernate.ejb.AbstractEntityManagerImpl.persist(AbstractEntityManagerImpl.java:678)
at alarm.Test.main(Test.java:32)
Caused by: org.hibernate.id.IdentifierGenerationException: ids for this class must be manually assigned before calling save(): alarm.ServiceAlarmConfEntity
at org.hibernate.id.Assigned.generate(Assigned.java:53)
at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:121)
at org.hibernate.ejb.event.EJB3PersistEventListener.saveWithGeneratedId(EJB3PersistEventListener.java:69)
I have two Entities having one-to-one relationship.
#Entity(name ="services")
#Table(name = "services")
public class Service implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#Column(name = "id")
private Integer id;
#Column(name = "label")
private String label;
#Column(name = "schemapath")
private String schemapath;
#Column(name = "customizedPath")
private String customizedPath;
#Column(name = "birimId")
private Integer birimId;
#Column(name = "alarmthresholdXML")
private String alarmthresholdXML;
#OneToOne(cascade = CascadeType.ALL, mappedBy = "service", fetch = FetchType.LAZY)
private ServiceAlarmConfEntity serviceAlarmConfEntity;
#Entity(name ="service_alarm_conf")
#Table(name = "service_alarm_conf")
public class ServiceAlarmConfEntity implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Basic(optional = false)
#Column(name = "service_id")
private Integer serviceId;
#Lob
#Column(name = "alarmthresholdXML")
private String alarmthresholdXML;
#Column(name = "alarmCheckEnable")
private Integer alarmCheckEnable;
#Column(name = "alarmDataTransferTimeInSeconds")
private Integer alarmDataTransferTimeInSeconds;
#JoinColumn(name = "service_id", referencedColumnName = "id", insertable = false, updatable = false)
#OneToOne(optional = false, fetch = FetchType.LAZY)
private Service service;
Main Class:
package alarm;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.EntityTransaction;
import javax.persistence.Persistence;
public class Test {
public static void main(String[] args) {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("alarm");
EntityManager em = emf.createEntityManager();
EntityTransaction tx = em.getTransaction();
Service service = new Service();
service.setLabel("Test1");
service.setBirimId(16);
service.setSchemapath("test1");
service.setCustomizedPath("Test1");
ServiceAlarmConfEntity serviceAlarmConfEntity = new ServiceAlarmConfEntity();
serviceAlarmConfEntity.setAlarmCheckEnable(1);
serviceAlarmConfEntity.setAlarmthresholdXML("alarmThresholdXML");
serviceAlarmConfEntity.setService(service);
service.setServiceAlarmConfEntity(serviceAlarmConfEntity);
tx.begin();
em.persist(service);
tx.commit();
em.close();
}
}
UPDATED:
ServiceAlarmConfEntity is configured as below. and it works.
#MapsId
#JoinColumn(name = "service_id", referencedColumnName = "id")
#OneToOne(optional = false, fetch = FetchType.LAZY)
private Service service;

The ID is only automatically generated if it's annotated with #GeneratedValue. But it isn't.
EDIT:
As explained in the documentation, the standard and recommended way to have the child entity share the ID of its parent entity is the following:
public class ServiceAlarmConfEntity {
#Id
private Integer serviceId;
#MapsId
#OneToOne(optional = false, fetch = FetchType.LAZY)
#JoinColumn(name = "service_id")
private Service service;
...
}

Related

How do I retrieve parent object with child object while having OneToMany bidriectional relationship in spring boot?

I am new to Spring boot. please help me with the below issue:
I am getting only child object data while retrieving using join query..
Below is my child entity class:
#Entity
#Table(name = "tenant_user_configuration")
public class TenantUserConfiguration {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
#Column(name = "config_key")
private String configKey;
#Column(name = "config_value")
private String configValue;
private String system;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name="tenant_user_id",referencedColumnName = "tenant_user_id")
#JsonBackReference
private TenantUser tenantUser;
This is my parent entity class:
#Entity
#Table(name = "tenant_user")
public class TenantUser {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "tenant_user_id")
private int tenantUserId;
#OneToOne
#JoinColumn(name = "tenant_id",referencedColumnName = "tenant_id")
private Tenant tenant;
#Column(name = "user_name")
private String userName;
#Column(name = "password")
private String password;
#Column(name = "enabled")
private boolean enabled;
#OneToMany(mappedBy = "tenantUser",fetch = FetchType.EAGER)
#JsonManagedReference
private Set<TenantUserConfiguration> tenantUserConfiguration = new HashSet<>();

Hibernate unexpected deletes when finding entities

We have a Java ee application running on JBoss 6.4 GA using JPA and Hibernate with the following entities:
#Entity
#SequenceGenerator(name = "sequence", sequenceName="SEQ_CAMPAIGNS_ID",allocationSize = 1)
#Table(name = "CAMPAIGN")
public class CampaignEntity implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequence")
#Column(name = "ID")
private Long id;
#Column(name = "NAME")
private String name;
#Column(name = "IS_ACTIVE", nullable = false)
private boolean active;
#Column(name = "START_DATE", nullable = false)
private Date startDate;
#Column(name = "END_DATE", nullable = false)
private Date endDate;
#Column(name = "LEGAL_ENTITY_ID", nullable = false)
private Integer legalEntityId;
#Column(name = "DEPARTMENT", nullable = false)
#Enumerated(value = EnumType.STRING)
private Department department;
#Column(name = "CATEGORY", nullable = false)
#Enumerated(value = EnumType.STRING)
private Category category;
#Embedded
CampaignConditionsEntity campaignConditions;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "campaign", orphanRemoval = true)
#OrderBy
private List<CodeEntity> campaignCodes;
public CampaignEntity() {
}
And the following CampaignConditionsEntity:
#Embeddable
public class CampaignConditionsEntity implements Serializable {
private static final String CAMPAIGN_ID = "CAMPAIGN_ID";
#ElementCollection(fetch = FetchType.EAGER)
#CollectionTable(name = "CAMPAIGN_COND_TRIP_TYPE", joinColumns = #JoinColumn(name = CAMPAIGN_ID))
private Set<TripTypeConditionEntity> tripTypeConditions;
And the following CodeEntity:
#Entity
#Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
#SequenceGenerator(name = "sequence", sequenceName = "SEQ_CODES_ID", allocationSize = 1)
public abstract class CodeEntity implements Serializable {
#Id
#GeneratedValue(strategy = GenerationType.SEQUENCE, generator = "sequence")
#Column(name = "ID", nullable = false)
private Long id;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name = "CAMPAIGN_ID")
private CampaignEntity campaign;
#OneToOne(mappedBy = "code", cascade = CascadeType.ALL, fetch = FetchType.LAZY, optional = false, orphanRemoval = true)
private DiscountEntity discount;
#Column(name = "MAX_USAGES", nullable = false)
private Integer maxUsages;
#Column(name = "UNLIMITED_USAGES", nullable = false)
private boolean unlimitedUsages;
#Column(name = "NEGATIVE_SH", nullable = false)
private boolean negativeSH;
#Column(name = "UNIQUE_BUYER", nullable = false)
private boolean uniqueBuyer;
#Column(name = "START_DATE")
private Date startDate;
#Column(name = "END_DATE")
private Date endDate;
#Embedded
private CodeConditionsEntity codeConditions;
public CodeEntity() {
}
This is the CodeConditionsEntity:
#Embeddable
public class CodeConditionsEntity implements Serializable {
private static final String CODE_ID = "CODE_ID";
#ElementCollection(fetch = FetchType.EAGER)
#CollectionTable(name = "CODE_COND_TRIP_TYPE", joinColumns = #JoinColumn(name = CODE_ID))
private Set<TripTypeConditionEntity> tripTypeConditions;
#ElementCollection(fetch = FetchType.EAGER)
#CollectionTable(name = "CODE_COND_CARRIERS", joinColumns = #JoinColumn(name = CODE_ID))
private Set<CarrierConditionEntity> carrierConditions;
This is the CarrierConditionEntity:
#Embeddable
public class CarrierConditionEntity implements Serializable {
#Column(name = "CARRIER", nullable = false, length = 3)
private String carrierCode;
#Column(name = "IS_INCLUDED", nullable = false)
private boolean included;
The problem is that in the logs we are finding unexpected deletes when the only operation that we are doing are finds of particular campaign entities.
In the production logs we find the following deletes
Hibernate: delete from CODE_COND_CARRIERS where CODE_ID=? and CARRIER=? and IS_INCLUDED=?
do you have any suggestion?
thanks
I have some suggestions :)
Be aware of what is a Persistence Context (EntityManager instance in JPA terminology / Session in Hibernate one), the entity lifecycle and transaction scope (unit of work)
Do not mutate entity state if you don't expect the changes to be reflected in database, or at least detach the entity before mutating it.
Mark your transaction as "readOnly" if you only fetch data in the related unit of work. (beware that if you have many "Transactional" methods joining the same physical transaction, the flag is set by the surrounding one and cannot be overridden by inner logical transactions). That way the EntityManager won't be flushed at the end of the transaction and pending changes won't be persisted to the database.
You can track the method triggering the unexpected deletion using an EntityListener on the related entity and printing the current strackTrace (new Throwable().printStackTrace()/ log(new Throwable()) in the PreRemove method
I found where was the problem:
The problem was that the Entities didn't have the equals() and the hashcode() implemented. Also there were entities that have a #PostLoad that modified the entity after loading it from database. Then in this situation Hibernate though that there was a change in those entities that didn't have the equals and the hashcode, and then it delete all of them and inserted again in the database (to have the same entities before the query)
Adding the equals and hashcode methods and deleting postload removed the unexpected deletes and inserts from the logs.
regards

how to resolve the 'save transient instance before saving' error on one to many relationship in hibernate jpa

this is the parent entity this is the child entityi have tried the suggested solution to similar error above but my application still spits out the same exception. please i need help
below is the exception
org.hibernate.TransientPropertyValueException: object references an unsaved transient instance - save the transient instance before flushing: com.domkat.springmvcjpa.model.Cpfaceleft1angle.cpftid -> com.domkat.springmvcjpa.model.Fromtocp
at org.hibernate.engine.spi.CascadingAction$8.noCascade(CascadingAction.java:380)
at org.hibernate.engine.internal.Cascade.cascade(Cascade.java:177)
at org.hibernate.event.internal.AbstractFlushingEventListener.cascadeOnFlush(AbstractFlushingEventListener.java:162)
at org.hibernate.event.internal.AbstractFlushingEventListener.prepareEntityFlushes(AbstractFlushingEventListener.java:153)
at org.hibernate.event.internal.AbstractFlushingEventListener.flushEverythingToExecutions(AbstractFlushingEventListener.java:89)
at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:51)
at org.hibernate.internal.SessionImpl.flush(SessionImpl.java:1234)
at org.hibernate.internal.SessionImpl.managedFlush(SessionImpl.java:404)
at org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction.beforeTransactionCommit(JdbcTransaction.java:101)
at org.hibernate.engine.transaction.spi.AbstractTransactionImpl.commit(AbstractTransactionImpl.java:175)
at org.hibernate.ejb.TransactionImpl.commit(TransactionImpl.java:75)
at org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:515)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.processCommit(AbstractPlatformTransactionManager.java:757)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.commit(AbstractPlatformTransactionManager.java:726)
at org.springframework.transaction.interceptor.TransactionAspectSupport.commitTransactionAfterReturning(TransactionAspectSupport.java:478)
at org.springframework.transaction.interceptor.TransactionAspectSupport.invokeWithinTransaction(TransactionAspectSupport.java:272)
at org.springframework.transaction.interceptor.TransactionInterceptor.invoke(TransactionInterceptor.java:95)
at org.springframework.aop.framework.ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:207)
at com.sun.proxy.$Proxy626.save(Unknown Source)
#Entity
#Table(name = "cpobservedhorizontalangles")
public class Cpobservedhorizontalangles implements Serializable {
private static final long serialVersionUID = 1L;
#Column(name = "degree")
private Integer degree;
#Column(name = "minute")
private Integer minute;
#Column(name = "second")
private Integer second;
#Column(name = "degminsec")
private String degminsec;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#Column(name = "ohaid")
private Integer ohaid;
#OneToMany(cascade={CascadeType.ALL},mappedBy = "ohaid")
private List<Cpfaceleft2angle> cpfaceleft2angleList;
#OneToMany(cascade={CascadeType.ALL},mappedBy = "ohaid")
private List<Cpfaceright2angle> cpfaceright2angleList;
#OneToMany(cascade={CascadeType.ALL},mappedBy = "ohaid")
private List<Cpfaceleft1angle> cpfaceleft1angleList;
#OneToMany(cascade={CascadeType.ALL},mappedBy = "ohaid")
private List<Cpfaceright1angle> cpfaceright1angleList;
...getters and setters... this is the child entity
#Entity
#Table(name = "cpfaceleft1angle")
public class Cpfaceleft1angle implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#Column(name = "id")
private Integer id;
#OneToMany(cascade={CascadeType.PERSIST},mappedBy = "cpfl1id")
private List<Fromtocp> fromtocpList;
#JoinColumn(name = "ohaid", referencedColumnName = "ohaid")
#ManyToOne
private Cpobservedhorizontalangles ohaid;
#JoinColumn(name = "faceid", referencedColumnName = "faceid")
#ManyToOne
private Faceleft faceid;
...getters and setters... this is the parent class but it contains other
entities
public class Fromtocp implements Serializable {
private static final long serialVersionUID = 1L;
// #Max(value=?) #Min(value=?)//if you know range of your decimal fields consider using these annotations to enforce field validation
#Column(name = "distance")
private Double distance;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#Column(name = "ftcpid")
private Integer ftcpid;
#Column(name = "diffleft")
private String diffleft;
#Column(name = "diffright")
private String diffright;
#Column(name = "meandiff")
private String meandiff;
#Column(name = "oadegdec")
private Double oadegdec;
#Column(name = "fb")
private Double fb;
#Column(name = "bb")
private Double bb;
#JoinColumn(name = "fromcp", referencedColumnName = "cpid")
#ManyToOne
private Controlpoints fromcp;
#JoinColumn(name = "cpfl1id", referencedColumnName = "id")
#ManyToOne
private Cpfaceleft1angle cpfl1id;
#JoinColumn(name = "cpfl2id", referencedColumnName = "id")
#ManyToOne
private Cpfaceleft2angle cpfl2id;
#JoinColumn(name = "cpfr1id", referencedColumnName = "id")
#ManyToOne
private Cpfaceright1angle cpfr1id;
#JoinColumn(name = "cpfr2id", referencedColumnName = "id")
#ManyToOne
private Cpfaceright2angle cpfr2id;
#JoinColumn(name = "tocp", referencedColumnName = "cpid")
#ManyToOne
private Controlpoints tocp;
...this is the other entity the parent class contains.
#Controller
public class SurveyController {
#Autowired
private SurveyService ss;
#Autowired
private ControlPointService cps;
#Autowired
private ScpService sps;
#Autowired
private CpobservedhorizontalanglesService cpos;
#Autowired
private Cpfaceleft1angleService cpfl1;
#Autowired
private Cpfaceleft2angleService cpfl2;
#Autowired
private Cpfaceright1angleService cpfr1;
#Autowired
private Cpfaceright2angleService cpfr2;
#Autowired
private FromTocpService ftcps;
#Autowired
private FaceleftService fls;
#Autowired
private FacerightService frs;
private Processor processor = new Processor();
HttpSession session;
#RequestMapping(value = "/surveydetails")
public String showSurveyDetailsPage(Model model) {
Surveys survey = new Surveys();
model.addAttribute("survey", survey);
return "SurveyDetails";
}
#RequestMapping(value = "/stations", method = RequestMethod.POST)
public String createSurvey(#RequestParam("surveyTitle") String title,
#RequestParam("cp1Label") String cp1Label, #RequestParam("cp1Northings") double northingsCp1,
#RequestParam("cp1Eastings") double eastingsCp1, #RequestParam("cp2Label") String cp2Label,
#RequestParam("cp2Northings") double northingsCp2, #RequestParam("cp2Eastings") double eastingsCp2,
#RequestParam("distance") double distance, #RequestParam("fl1Deg") int fl1Deg,
#RequestParam("fl1Min") int fl1Min, #RequestParam("fl1Sec") int fl1Sec,
#RequestParam("fl2Deg") int fl2Deg, #RequestParam("fl2Min") int fl2Min, #RequestParam("fl2Sec") int fl2Sec,
#RequestParam("fr1Deg") int fr1Deg, #RequestParam("fr1Min") int fr1Min, #RequestParam("fr1Sec") int fr1Sec,
#RequestParam("fr2Deg") int fr2Deg, #RequestParam("fr2Min") int fr2Min, #RequestParam("fr2Sec") int fr2Sec) {
Surveys survey = new Surveys();
Scp scp = new Scp();
Signups su = null;
Cpobservedhorizontalangles o1 = new Cpobservedhorizontalangles();
o1.setDegree(fl1Deg);
o1.setMinute(fl1Min);
o1.setSecond(fl1Sec);
o1.setDegminsec(processor.degToString(fl1Deg, fl1Min, fl1Sec));
Cpfaceleft1angle fl1 = new Cpfaceleft1angle();
fl1.setOhaid(o1);
fl1.setFaceid(faceleft1);
cpos.save(o1);
cpfl1.save(fl1);
please help. thanks
i have resolved the problem. And in addition i found out how i can actually save just the parent class by calling the save method on the parent and then it saves the child entities as well. jpa makes it quite easy.
i will use an illustration of employee and address. lets say an employee can have more than one address it means we will have two tables in the database and two entity classes, one for each of these tables right?. it also means that the employee table becomes the parent table while the address becomes the child table right? the code below just shows how you can save the parent class and by the saving the parent class the child entities get saved as well! all you do is set the parent object(in this case the employee) on the child object(in this case the address), then set the List(the list of child in this case is address. so it becomes List) on the parent entity. then call the save method on the parent.
...necessary imports...
#Entity
#Table(name = "address")
#NamedQueries({
#NamedQuery(name = "Address.findAll", query = "SELECT a FROM Address a")})
public class Address implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#Column(name = "address_id")
private Integer addressId;
#Column(name = "employee_address")
private String employeeAddress;
#JoinColumn(name = "employee_id", referencedColumnName = "employee_id")
#ManyToOne
private Employee employeeId;
public Address() {
}
...getters and setters for this entity...
#Entity
#Table(name = "employee")
#NamedQueries({
#NamedQuery(name = "Employee.findAll", query = "SELECT e FROM Employee e")})
public class Employee implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#Column(name = "employee_id")
private Integer employeeId;
#Column(name = "name")
private String name;
#Column(name = "email")
private String email;
#Column(name = "phone")
private String phone;
#OneToMany(cascade=CascadeType.ALL,mappedBy = "employeeId")
private List<Address> addressList;
public Employee() {
}
...getters and setters for this class...
...below is the class that makes use of the entities...
public class SaveExample {
public static void main(String[] args) {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("JPAJoinTableTutorialsPU");
EntityManager em = emf.createEntityManager();
em.getTransaction().begin();
Employee employee = new Employee();// employee object
Address address = new Address(); // Address Object
address.setEmployeeAddress("set the value");
address.setEmployeeId(employee);
List<Address>addressList=new ArrayList<>();
addressList.add(address);
employee.setEmail("set the value");
employee.setName("set the value for name");
employee.setPhone("set the value");
employee.setAddressList(addressList);
em.persist(employee);
em.getTransaction().commit();
}
}
i hope that helps some people..thanks

JPA: data table after insert doesnt show the #joincolumn #ManyToOne

I'm trying a web project using JPA and JSF-primefaces.
I have a bug with insert/update an object which has #ManyToOne relationship.
after inserting, #JoinColumn is blank field. (sorry ican't post image, this is image link)
after insert
and then, after reload list, blank field is back to normal
after reload
I'm using unidirectional #ManyToOne entity
Place.java
#Entity
#Table(name = "place")
#XmlRootElement
public class Place implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Basic(optional = false)
#Column(name = "id")
private Integer id;
...
#Basic(optional = false)
#NotNull
#Column(name = "prefecture_id")
private int prefectureId;
#ManyToOne(fetch = FetchType.EAGER, cascade = CascadeType.ALL)
#JoinColumn(name = "prefecture_id",referencedColumnName = "id", updatable = false,insertable = false)
private Aken prefecture;
Aken.java
#Entity
#Table(name = "aken")
#XmlRootElement
public class Aken implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Basic(optional = false)
#NotNull
#Column(name = "id")
private Short id;
#Size(max = 50)
#Column(name = "data")
private String data;
method update to database
#Stateless
#TransactionManagement(TransactionManagementType.BEAN)
public class PlaceFacade extends AbstractFacade<Place> {
#PersistenceContext(unitName = "JutenPU")
private EntityManager em;
#Resource
private UserTransaction userTransaction;
public void edit(Place place){
try{
getUserTransaction().begin();
getEntityManager().merge(place);
getUserTransaction().commit();
}catch(Exception e){
System.out.println(e.getMessage());
}
}
method retrieve data on table
public List<Place> findAll() {
javax.persistence.criteria.CriteriaQuery cq = getEntityManager().getCriteriaBuilder().createQuery();
cq.select(cq.from(Place.class));
return getEntityManager().createQuery(cq).getResultList();
}
I'm using JAVA EE7, glassfish server 4, primefaces 4.0
Thanks for your help
#JoinColumn(name = "prefecture_id",referencedColumnName = "id", updatable = false,insertable = false)
you marked Place foreign key column READONLY.
remove limitations: #JoinColumn(name = "prefecture_id",referencedColumnName = "id")

SAXException2: A cycle is detected in the object graph. What is the case?

I have a web-service with Java class files that have been generated with NetBeans based on the database schema I have.
I get strange exceptions sometimes and one of them is this one:
javax.xml.ws.WebServiceException: javax.xml.bind.MarshalException
- with linked exception:
[com.sun.istack.internal.SAXException2: A cycle is detected in the object graph. This will cause infinitely deep XML: org.mylib.Person[ personId=1 ] ->org.mylib.TeamPerson[ teamPersonPK=org.mylib.teamPersonPK[ teamId=1, personId=1 ] ] -> org.mylib.Person[ personId=1 ]]
I have googled this exception and found some simillar cases but I still cannot understand the problem. I have just generated those classes (Person.java, Team.java, TeamPerson.java) with NetBeans so how can the problem occur?
This happens when I try to get all Persons:
Iterator iter = team.getTeamPersonCollection().iterator();
while(iter.hasNext()) {
Person person = ((TeamPerson)iter.next()).getPerson();
...
}
EDIT
If I remove the Team reference from TeamPerson I get the following error:
Internal Exception: Exception [EclipseLink-7154] (Eclipse Persistence Services - 2.2.0.v20110202-r8913): org.eclipse.persistence.exceptions.ValidationException
Exception Description: The attribute [teamPersonCollection] in entity class [class org.mylib.Team] has a mappedBy value of [team] which does not exist in its owning entity class [org.mylib.TeamPerson]. If the owning entity class is a #MappedSuperclass, this is invalid, and your attribute should reference the correct subclass.
at org.eclipse.persistence.exceptions.PersistenceUnitLoadingException.exceptionSearchingForPersistenceResources(PersistenceUnitLoadingException.java:126)
EDIT 2
Parts of the generated classes looks like this:
Team.java
public class Team implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Basic(optional = false)
#Column(name = "team_id")
private Integer teamId;
#Column(name = "type")
private String type;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "team")
private Collection<TeamPerson> teamPersonCollection;
Person.java
public class Person implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#Basic(optional = false)
#Column(name = "person_id")
private Integer personId;
#Column(name = "name")
private String name;
#OneToMany(cascade = CascadeType.ALL, mappedBy = "person")
private Collection<TeamPerson> teamPersonCollection;
TeamPerson.java
public class TeamPerson implements Serializable {
private static final long serialVersionUID = 1L;
#EmbeddedId
protected TeamPersonPK teamPersonPK;
#Basic(optional = false)
#Column(name = "timestamp")
#Temporal(TemporalType.TIMESTAMP)
private Date timestamp;
#JoinColumn(name = "team_id", referencedColumnName = "team_id", insertable = false, updatable = false)
#ManyToOne(optional = false)
private Team team;
#JoinColumn(name = "person_id", referencedColumnName = "person_id", insertable = false, updatable = false)
#ManyToOne(optional = false)
private Person person;
TeamPersonPK.java
#Embeddable
public class TeamPersonPK implements Serializable {
#Basic(optional = false)
#Column(name = "team_id")
private int teamId;
#Basic(optional = false)
#Column(name = "person_id")
private int personId;
The solution is simply to add the annotation : "#XmlTransient" (javax.xml.bind.annotation.XmlTransient) at the getter of the property that causes the cycle.
Well maybe thats is because your Person class contains the field of type TeamPerson and the TeamPerson contains the field of type Person. And the marshaller is confused un parsing such loop init?
UPD. Maybe you need to change this
#OneToMany(cascade = CascadeType.ALL, mappedBy = "team")
private Collection<TeamPerson> teamPersonCollection;
to:
#OneToMany(cascade = CascadeType.ALL, mappedBy = "teamId")
private Collection<TeamPerson> teamPersonCollection;
because field team does not exist in class TeamPerson?

Categories