Hi,
I may've found a bug in Hibernate Validator using @NotEmpty on a One-To-Many parent child association.
Abstract
Given is a parent child relation with @NotEmtpy on the @OneToMany "parent has childs" association in the parent entity.
Persisting a newly created parent with one child using session.saveOrUpdate(parent) works, while session.merge(parent) throws an InvalidStateException.
Both, saveOrUpdate(...) and merge(...), throw the expected InvalidStateException if a parent entity without a child entity is persisted.
Hibernate version: 3.2.4.sp1
Validator version: 3.0.0.ga
Mapping:
Code:
@Entity
public class Parent {
@Id @GeneratedValue private Long id;
@OneToMany(mappedBy = "parent")
@org.hibernate.annotations.Cascade( { org.hibernate.annotations.CascadeType.ALL } )
@NotEmpty(message = "is empty")
public List<Child> childs = new ArrayList<Child>();
}
@Entity
public class Child {
@Id @GeneratedValue private Long id;
@ManyToOne()
@JoinColumn(name = "parentId")
@NotNull
public Parent parent;
}
Code between sessionFactory.openSession() and session.close():Parent p = new Parent();
Child c = new Child();
p.childs.add(c);
c.parent = p;
Test 1: works!
session.saveOrUpdate(p);
session.flush();
Test 2: throws an InvalidStaeException
// this statements are of course executed in a different session, not after session.saveOrUpdate(p)
session.merge(p); // the exception is thrown here
session.flush();
The InvalidStateException transports one InvalidValue object
InvalidValue.getPropertyName() = "childs"
InvalidValue.getMessage() = "is empty"
Full stack trace of any exception that occurs:Code:
Caused by: org.hibernate.validator.InvalidStateException: validation failed for: test.Parent
at org.hibernate.validator.event.ValidateEventListener.validate(ValidateEventListener.java:143)
at org.hibernate.validator.event.ValidateEventListener.onPreInsert(ValidateEventListener.java:167)
at org.hibernate.action.EntityIdentityInsertAction.preInsert(EntityIdentityInsertAction.java:119)
at org.hibernate.action.EntityIdentityInsertAction.execute(EntityIdentityInsertAction.java:42)
at org.hibernate.engine.ActionQueue.execute(ActionQueue.java:250)
at org.hibernate.event.def.AbstractSaveEventListener.performSaveOrReplicate(AbstractSaveEventListener.java:298)
at org.hibernate.event.def.AbstractSaveEventListener.performSave(AbstractSaveEventListener.java:181)
at org.hibernate.event.def.AbstractSaveEventListener.saveWithGeneratedId(AbstractSaveEventListener.java:107)
at org.hibernate.event.def.DefaultMergeEventListener.entityIsTransient(DefaultMergeEventListener.java:186)
at org.hibernate.event.def.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:123)
at org.hibernate.event.def.DefaultMergeEventListener.onMerge(DefaultMergeEventListener.java:53)
at org.hibernate.impl.SessionImpl.fireMerge(SessionImpl.java:677)
at org.hibernate.impl.SessionImpl.merge(SessionImpl.java:661)
at org.hibernate.impl.SessionImpl.merge(SessionImpl.java:665)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.jboss.ejb3.entity.hibernate.TransactionScopedSessionInvocationHandler.invoke(TransactionScopedSessionInvocationHandler.java:98)
at $Proxy131.merge(Unknown Source)
... 91 more
Regards,
Ron