-
1. Re: Entity level validation
evdelst Apr 16, 2009 1:50 PM (in response to francof)A Class level validator would be the cleanest solution.
However, Seam doesn't evaluatie those validations on a form submit.
Hibernate will throw an exception during the persist if such a validator fails...What you can do is the following:
- create a validator
- call the validator before the persist method
- add any invalid values to the FacesMessage and return null (forces re-display of the page)
Example:
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) @ValidatorClass(PersonValidatorImpl.class) public @interface PersonValidator { String message() default "person validation fails"; }
public class PersonValidatorImpl implements Validator<PersonValidator> { public void initialize(PersonValidator arg0) { } public boolean isValid(Object arg0) { Person p = (Person) arg0; if (p.getName().contains("edwin")) { return false; } return true; } }
In PersonHome (assuming you subclass EntityHome)
@Override public String persist() { ClassValidator<Person> validator = new ClassValidator<Person>(Person.class); InvalidValue[] invalidValues = validator.getInvalidValues(this.instance); if (invalidValues.length>0) { for (InvalidValue v : invalidValues) { FacesMessages.instance().add(v); } return null; } return super.persist(); }
Don't forget to put a <h:messages globalOnly=true> in the template to display the validation errors!
-
2. Re: Entity level validation
francof Apr 16, 2009 3:42 PM (in response to francof)Edwin,
This is exactly what I finished with yesterday :)
Thank you very much for taking the time to help, I really appreciate it.
Regards
Franco
-
3. Re: Entity level validation
francof Apr 16, 2009 9:06 PM (in response to francof)My only beef with this approach is that I cannot create custom messages (or maybe I don't know how) for each failed validation.
@CatalogItemValidator( message = "Validation failed while inserting/updating this entity") public class CatalogItem { .. }
public @interface CatalogItemValidator { String message() default "{validator.catalogitem.invalid}"; }
public class CatalogItemValidatorImpl implements Validator<CatalogItemValidator>, Serializable { public boolean isValid(Object value) { boolean isValid = true; CatalogItem catalogItem = (CatalogItem) value; java.util.Date startDt = (java.util.Date) catalogItem.getFeatureStartDate(); java.util.Date endDt = (java.util.Date) catalogItem.getFeatureEndDate(); if ( startDt != null && endDt != null ) { isValid = endDt.after(startDt) || endDt.equals(startDt) ; ////want custom message here } startDt = (java.util.Date) catalogItem.getWebStartDate(); endDt = (java.util.Date) catalogItem.getWebEndDate(); if ( startDt != null && endDt != null ) { isValid = endDt.after(startDt) || endDt.equals(startDt) ; ////want custom message here } return isValid; } }
I always get the message that I sent in as the parameter. It gives me no clue as to which field failed the validation.
One approach I thought of was to declare a transient variable on the entity itself.
@Entity public class CatalogItem { List<InvalidValue> errors = new ArrayList<InvalidValue>(); //getters, setters }
then from the custom validator store all the errors here.
Does anyone have any other solutions ?
Thanks
Franco -
4. Re: Entity level validation
josdaniel Feb 12, 2010 8:01 AM (in response to francof)We are also looking for raising custom messages for different conditions, is there a cleaner way to achieve that from within the class level validator.
-
5. Re: Entity level validation
serkan.s.eskici.online.nl Feb 23, 2010 11:30 PM (in response to francof)What you also could do in this case is the following in your Entity Bean:
//this is a Hibernate Validator on your method @AssertTrue(message="date1 must be less than date2") public boolean validateDate() { if(date1 != null && date2 != null) return date1.compareTo(date2) < 0; return true; }
if you've annotated your fields in stead of your getters in your Entity Bean, then you'll have to add a boolean field with @AssertTrue on it and implement this logic in the getter.
Another alternative:
http://seamframework.org/Community/ComponentgetInstanceInsidedAPrePersistMethod -
6. Re: Entity level validation
josdaniel Feb 24, 2010 8:25 AM (in response to francof)I have already tried your suggestion before, by adding @AssertTrue and it still fails because it is not bound to the Entity member variable and it doesn't get surfaced to the UI.
For the time being we have moved these checks to EntityHome.persist / update methods