Hi all,
First of all, thanks to Emmanuel for leading the spec. This is a major step forward for reusing business validation logic in different tiers and in a standard way. I hope there will be a 1.1 and 2.0 verion of this spec!
We read both the doc and the forum and We've not found a proper way to do conditional validation. Perhaps we missed the point how to do that.
Our business case is quite simple. We need to validate a bean containing MSISDN and IMSI (telecom industry). We need to ensure that at least one field is valid.
Code:
public class MyBean {
private String msisdn;
private String imsi;
}
For validating MSISDN we've created a composite annotation:
Code:
@NotBlank
@Pattern(regexp="^\\d{12}$")
@ReportAsSingleViolation
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = {})
@Documented
public @interface MSISDN {
String message() default "{com.acme.domain.constraint.MSISDN.message}";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
And we did the same for IMSI:
Code:
@NotBlank
@Pattern(regexp="^\\d{15}$")
@ReportAsSingleViolation
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = {})
@Documented
public @interface IMSI {
String message() default "{com.acme.domain.constraint.IMSI.message}";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
Then we created the custom constraint for validating the bean:
Code:
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = {AtLeastOneValidValidator.class})
@Documented
public @interface AtLeastOneValid {
String message() default "{com.acme.interfaces.ws.constraint.AtLeastOneValid.message}";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
And the related validator that we'd want to implement:
Code:
public class AtLeastOneValidValidator implements ConstraintValidator<AtLeastOneValid, Object> {
@Override
public void initialize(AtLeastOneValid constraintAnnotation) {
}
@Override
public boolean isValid(Object value, ConstraintValidatorContext context) {
String str = (String) BeanUtils.getProperty(value, "msisdn");
// Dynamic validation of our composite constraint
AnnotationDescriptor<MSISDN> descriptor = new AnnotationDescriptor<MSISDN>(MSISDN.class);
MSISDN msisdn = AnnotationFactory.create(descriptor);
// This class does not exist yet
// CompositeConstraintValidator<MSISDN, String> validator = new CompositeConstraintValidator<MSISDN, String>();
// validator.initialize(msisdn);
//
// if (validator.isValid(str, context)) {
// return true;
// } else {
//
//
// }
}
}
We expected to find out a Validator class (see the code of our AtLeastOneValidValidator) in the framework for validating composite constraint (e.g. CompositeConstraintValidator) and we've not found a related class to do that. So, is this a lack of the framework? I'm quite sure the framework needs the same logic for validating composite constraints, but perhaps the code is spread out among several classes.
We know that if we implement MSISDN and IMSI validator we could use them in AltLeastOneValidValidtor. But as we define our constraints with composite constraint we want to reuse them (DRY principle).
If someone knows the trick to do the same thing in different and simplier way, we are interested in.
Any help would be greatly appreciated,
Regards,
Alexandre