0

I've just started testing JSR-303 Bean validation and was wondering if something was possible. We have a default regular expression in our app for all String fields. If I want to apply this using bean validation I think I need to annotate each field within my form object.

@Pattern(regexp = REG_EXP)
private String aString;

@Pattern(regexp = REG_EXP)
private String anotherString;

Is it possible to apply the @Pattern to all Strings (or certain fields) in one hit? We're using the Hibernate implementation on Weblogic 10.3.4 with JSF2.0 as the front end. Validation should be independent of view as I may be coming in from a webservice.

andyfinch
  • 1,312
  • 2
  • 19
  • 34

2 Answers2

2

To validate more than one field at once, use an annotation on type-Level and write a custom Validator that checks all String fields using your REGEXP.

Edit: Provide example. This is quite ugly, because it uses Reflection and violates security, but maybe it gives you a general idea. If you dont use "object" but a concrete class or interface, you could possibly have success with regular getters.

The Class under Test (and the Runner)

   import javax.validation.Validation;
import javax.validation.Validator;

import validation.AllStringsRegex;

@AllStringsRegex(value="l")
public class UnderValidation {
    String a;
    String b;

   public static void main(String... args) {
       UnderValidation object = new UnderValidation();
       object.a = "hello";
       object.b = "world";

       Validator validator = Validation.buildDefaultValidatorFactory().getValidator();
       System.out.println(validator.validate(object));
   }
}

My Annotation:

@Target( { TYPE, ANNOTATION_TYPE })
@Retention(RUNTIME)
@Constraint(validatedBy = AllStringsRegexValidator.class)
@Documented
public @interface AllStringsRegex {
    String message() default "String not regex";
    String value() default "";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
}

My Validator

public class AllStringsRegexValidator implements ConstraintValidator<AllStringsRegex, Object> {
    private Pattern pattern = null;

    @Override
    public void initialize(AllStringsRegex annotation) {
        pattern = Pattern.compile(annotation.value());
    }

    @Override
    public boolean isValid(Object object, ConstraintValidatorContext ctx) {
        for (Field f : object.getClass().getDeclaredFields()) {
            if (f.getType().equals(String.class)) {
                try {
                    f.setAccessible(true);
                    String value = (String)f.get(object);
                    if (!pattern.matcher(value).find()) {
                        return false;
                    }
                }
                catch (Exception e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }
        return true;
    }
}
Jan Galinski
  • 11,768
  • 8
  • 54
  • 77
  • Thanks but @type is not validated by JSF. But how would a custom Validator check ALL the String fields? – andyfinch Mar 21 '12 at 15:31
  • in the example above, no error is thrown, because "l" matches both "hello" and "world". change to "ll" to get a ConstraintViolation. – Jan Galinski Mar 21 '12 at 22:49
  • Thank Jan, very good example and I learned some new stuff from it. – andyfinch Mar 22 '12 at 08:38
  • Jan, a further question. Can you explain your negative comments regarding Reflection and Security. Thanks. – andyfinch Mar 22 '12 at 09:23
  • 1
    Security: I use "setAccessible" to access the field value directly. This violates the encapsulation contract (private attributes, public getters/setters). Any production system will block this, so this is only for testing and poc. Refelection: Reflection can get slow, and it violates the object-oriented approach. As I mentioned: try writing a Validator for a Concrete class (Customer instead of Object) and then drop the reflection part but access the values via concrete getters (getName(), get() ...) – Jan Galinski Mar 22 '12 at 11:37
0

I didnt use but java supporting scripting in server side using grovvy ,javascript.. .You can check @ScriptAssert(lang = "javascript", script =_this.startDate.before(_this.endDate) scripting annotation which is hibernate annotation.

ayengin
  • 1,606
  • 1
  • 22
  • 47
  • Thanks but I've just edited my question as validation needs to run regardless of access method i.e. via Webservice or Browser. – andyfinch Mar 21 '12 at 12:02