Help

Antonio has written a nice article on how to use Bean Validation and Hibernate Validator 4.0 in JPA 1.0 and Hibernate 3.3 (by retrofitting what's happening automatically in JPA 2.0). He asked an interesting question at the end of his post.

While he understands the benefit of JPA 2.0 calling Bean Validation on entity creation or update, he is wondering about the use case driving the ability to trigger validation when an entity is removed.

The feature was not in initially but a user came with an interesting use case during the review process:

I want to be sure an order is paid before deleting it from the system. If it's not paid, I am not legally allowed to remove it.

Here is the solution:

@Entity class Order {
   @Id @GeneratedValue public Integer getId() { return id; }
   public void setId(Integer id) { this.id = id; }
   private Integer id;

   @AssertTrue(groups=LegallyRemovable.class) public boolean isPaid() { return paid; }
   public void setPaid(boolean paid) { this.paid = paid; }
   private boolean paid;

   [...]
}

<persistence-unit name="OrderManagement">
  <properties>
    <property name="javax.persistence.validation.group.pre-remove">com.acme.app.groups.LegallyRemovable</property>
  </properties>
</persistence-unit>

The application will likely do something like that at the service layer:

if ( validator.validate(order, LegallyRemovable.class).size() > 0 ) {
  throw BusinessException(...);
}

But if for some reason a developper forgets to do it or an order is deleted by cascade, the JPA 2 validation layer will be here to save you.

Note that by default, no group is validated when entities are removed which makes sense for 99% of the use cases out there.

6 comments:
 
03. Mar 2010, 23:07 CET | Link

Out of curiosity, is there a way to define what validations get run at what JPA events via annotations?

ReplyQuote
 
04. Mar 2010, 00:25 CET | Link
Drew wrote on Mar 03, 2010 17:07:
Out of curiosity, is there a way to define what validations get run at what JPA events via annotations?

No. But if you've got a use case for it, feel free to elaborate.

 
04. Mar 2010, 02:38 CET | Link

Hi Emmanuel,

I wrote about that topic in my post JPA 2 and Bean Validation in Action, too:

http://musingsofaprogrammingaddict.blogspot.com/2010/01/jpa-2-and-bean-validation-in-action.html

The scenario there is similar, customers are only allowed to be deleted, if they have been archived on some kind of long-time storage.

Gunnar

 
04. Mar 2010, 22:21 CET | Link
Paul Mooney | paul.mooney(AT)live.com
Emmanuel Bernard wrote on Mar 03, 2010 18:25:
Drew wrote on Mar 03, 2010 17:07:
Out of curiosity, is there a way to define what validations get run at what JPA events via annotations?
No. But if you've got a use case for it, feel free to elaborate.

Taking the use case you described above where an order can only be deleted if it is payed: During other events like insert or update the order doesn't have to be payed yet so this validation shouldn't be triggered.

 
07. Mar 2010, 17:22 CET | Link
Paul Mooney wrote on Mar 04, 2010 16:21:
Emmanuel Bernard wrote on Mar 03, 2010 18:25:
Drew wrote on Mar 03, 2010 17:07:
Out of curiosity, is there a way to define what validations get run at what JPA events via annotations?
No. But if you've got a use case for it, feel free to elaborate.
Taking the use case you described above where an order can only be deleted if it is payed: During other events like insert or update the order doesn't have to be payed yet so this validation shouldn't be triggered.

The order must be validated but the fact that an order is paid or not does not make it valid or not. So constraints using the Default group are validated. That's why I use a dedicated group for the LegallyRemovable constraints.

You can change the group being validated at insert time and update time however using the persistence.xml construct

<persistence-unit name="OrderManagement">
  <properties>
    <property name="javax.persistence.validation.group.pre-persist">com.acme.app.groups.MyGroup</property>
    <property name="javax.persistence.validation.group.pre-update">com.acme.app.groups.MyOtherGroup</property>
  </properties>
</persistence-unit>
 
12. Aug 2011, 16:18 CET | Link

Hi Emmanuel,

this type of validation is possible using a class-level annotation? @Target({ElementType.TYPE})

using the same context the refactored use case may be:

I want to be sure an order has no items before deleting it from the system. If it has at least one item, I am not legally allowed to remove it.

Imagining that Order has no bi-directional mapping with Item.

Thanks in advance.

Post Comment