org.hibernate.validator.InvalidStateException: validation failed for : my.package.A

Hibernate JIRA | Julien Kronegg | 8 years ago
tip
Click on the to mark the solution that helps you, Samebug will learn from it.
As a community member, you’ll be rewarded for you help.
  1. 0

    According to Hibernate validation documentation ( http://www.hibernate.org/hib_docs/validator/reference/en/html_single/#validator-checkconstraints-orm-jpaevent ) we can annotate an entity with @EntityListeners({JPAValidateListener.class}) to validate the fields using the @PrePersist / @PreUpdate JPA events handlers. I tryied with the following entity: @Entity @Table(...) @EntityListeners({JPAValidateListener.class}) public class A { private int id; private String text; @Id @Column(...) @NotNull @GeneratedValue(...) @GenericGenerator(...) public int getId() { return id; } public void setId(int id) { this.id=id; } ... } Problem is that the @PrePersist event is raised before some fields are automatically filled (e.g. @Id annotated). So the JPAValidateListener raises an exception saying that the identifier cannot be null. The exception root cause detail is (InvalidState: id cannot be null) and the stacktrace is: org.hibernate.validator.InvalidStateException: validation failed for : my.package.A at org.hibernate.validator.ClassValidator.assertValid(ClassValidator.java:666) at org.hibernate.validator.event.JPAValidateListener.onChange(JPAValidateListener.java:62) ...// some reflection StacktraceElement at org.hibernate.ejb.event.ListenerCallback.invoke(ListenerCallback.java:31) at org.hibernate.ejb.event.EntityCallbackHandler.callback(EntityCallbackHandler.java:80) at org.hibernate.ejb.event.EntityCallbackHandler.preCreate(EntityCallbackHandler.java:49) at org.hibernate.ejb.event.EJB3PersistEventListener.saveWithGeneratedId(EJB3PersistEventListener.java:48) at org.hibernate.event.DefaultPersistEventListener.entityIsTransient(DefaultPersistEventListener.java:154) at org.hibernate.event.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:110) at org.hibernate.event.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:61) at org.hibernate.impl.SessionImpl.firePersist(SessionImpl.java:645) at org.hibernate.impl.SessionImpl.persist(SessionImpl.java:619) at org.hibernate.impl.SessionImpl.persist(SessionImpl.java:623) ... The EJB3PersistEventListener.saveWithGeneratedId() method looks like: protected Serializable saveWithGeneratedId(...) { callbackHandler.preCreate(entity); // raises the @PrePersist JPA event return super.saveWithGeneratedId(...); // sets the identifier } Thus, the JPAValidateListener validates the whole Entity and does not take the entity lifecycle into account. The JPAValidateListener should check all fields except the ones which are known to be modified/setled after the call to the validator. This may also be the case for other generated fields such as the ones annotated with @Version (I did not check that).

    Hibernate JIRA | 8 years ago | Julien Kronegg
    org.hibernate.validator.InvalidStateException: validation failed for : my.package.A
  2. 0

    According to Hibernate validation documentation ( http://www.hibernate.org/hib_docs/validator/reference/en/html_single/#validator-checkconstraints-orm-jpaevent ) we can annotate an entity with @EntityListeners({JPAValidateListener.class}) to validate the fields using the @PrePersist / @PreUpdate JPA events handlers. I tryied with the following entity: @Entity @Table(...) @EntityListeners({JPAValidateListener.class}) public class A { private int id; private String text; @Id @Column(...) @NotNull @GeneratedValue(...) @GenericGenerator(...) public int getId() { return id; } public void setId(int id) { this.id=id; } ... } Problem is that the @PrePersist event is raised before some fields are automatically filled (e.g. @Id annotated). So the JPAValidateListener raises an exception saying that the identifier cannot be null. The exception root cause detail is (InvalidState: id cannot be null) and the stacktrace is: org.hibernate.validator.InvalidStateException: validation failed for : my.package.A at org.hibernate.validator.ClassValidator.assertValid(ClassValidator.java:666) at org.hibernate.validator.event.JPAValidateListener.onChange(JPAValidateListener.java:62) ...// some reflection StacktraceElement at org.hibernate.ejb.event.ListenerCallback.invoke(ListenerCallback.java:31) at org.hibernate.ejb.event.EntityCallbackHandler.callback(EntityCallbackHandler.java:80) at org.hibernate.ejb.event.EntityCallbackHandler.preCreate(EntityCallbackHandler.java:49) at org.hibernate.ejb.event.EJB3PersistEventListener.saveWithGeneratedId(EJB3PersistEventListener.java:48) at org.hibernate.event.DefaultPersistEventListener.entityIsTransient(DefaultPersistEventListener.java:154) at org.hibernate.event.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:110) at org.hibernate.event.DefaultPersistEventListener.onPersist(DefaultPersistEventListener.java:61) at org.hibernate.impl.SessionImpl.firePersist(SessionImpl.java:645) at org.hibernate.impl.SessionImpl.persist(SessionImpl.java:619) at org.hibernate.impl.SessionImpl.persist(SessionImpl.java:623) ... The EJB3PersistEventListener.saveWithGeneratedId() method looks like: protected Serializable saveWithGeneratedId(...) { callbackHandler.preCreate(entity); // raises the @PrePersist JPA event return super.saveWithGeneratedId(...); // sets the identifier } Thus, the JPAValidateListener validates the whole Entity and does not take the entity lifecycle into account. The JPAValidateListener should check all fields except the ones which are known to be modified/setled after the call to the validator. This may also be the case for other generated fields such as the ones annotated with @Version (I did not check that).

    Hibernate JIRA | 8 years ago | Julien Kronegg
    org.hibernate.validator.InvalidStateException: validation failed for : my.package.A

    Root Cause Analysis

    1. org.hibernate.validator.InvalidStateException

      validation failed for : my.package.A

      at org.hibernate.validator.ClassValidator.assertValid()
    2. Hibernate Validator Engine
      ClassValidator.assertValid
      1. org.hibernate.validator.ClassValidator.assertValid(ClassValidator.java:666)
      1 frame
    3. org.hibernate.validator
      JPAValidateListener.onChange
      1. org.hibernate.validator.event.JPAValidateListener.onChange(JPAValidateListener.java:62)
      1 frame