[bv-dev] Cross parameter validation convergence

Matt Benson mbenson at apache.org
Wed Aug 29 11:38:29 EDT 2012


On Wed, Aug 29, 2012 at 4:03 AM, Emmanuel Bernard
<emmanuel at hibernate.org> wrote:
> I would like to bring home cross parameter validation which is one of the main open issues in method validation.
> We have been discussing it for literally 11 months, it's time to converge. If you could give your feedback quickly, Gunnar
> might be able to add it to the spec in the next few days. I am already pushing him harder than I should to
> move BV forward so give him some help :)
>
> The following is a less readable copy of what you can find at http://beanvalidation.org/proposals/BVAL-232/
>
> ### Cross parameter validation and return value
>
> Do we agree that validating both the parameters and the return value in a single
> constraint validator is not a use case we want to cover?
> To me that would be awkward to support it as we would need to execute the method
> to validate it.
>

+1, yet nothing should be done to preclude adding this in a later
version of the spec.

> ### Where to host cross-parameter constraints
>
> We use the method as host to the return value constraints and possibly `@Valid`.
> That is unfortunately also the natural place for cross parameter constraints.
>
> I cannot think of another place to put them. There is also no easy way to add a
> visual cue and differentiate a regular constraint from a cross param constraint
> except by its meta annotation. We would rely on the user adding a visual cue in
> the constraint name. Which kind of cue? Put `param` in the constraint name?

In the end this is not something that should be enforced anyway, so I
suspect far too much thought has been given to it already.  ;)  Using
the CheckRetypedPasswordParameter example, I would personally prefer
CheckRetypedPasswordParams and extrapolate that to "ends with
'Params'".  Find an example or two everyone is comfortable with,
extrapolate a *recommendation* as in the example of . at List for
multiple constraints and move on.  :)

>
> Any one can think of a better approach?

Nothing from me.

>
> #### Bean Validation class
>
>     @interface CrossParameterConstraint {
>         public Class<? extends CrossParameterConstraintValidator<?, ?>>[] validatedBy();
>     }

Why <?, ?> on the CPCV signature?  I assume this is an error as it's
not consistent with the CheckRetypedPasswordValidator example below.

>
>     interface CrossParameterConstraintValidator<A extends Annotation> {
>         void initialize(A constraintAnnotation);
>         [...]
>     }
>
>> Question: does these different annotations/interfaces affect the metadata API?

I haven't looked at the metadata API in depth where it applies to
method validation, but it might be nice to differentiate
cross-parameter constraints from return value constraints at the
metadata level to save users the trouble.

>>
>> Question: can the same constraint annotation be annotated by both
>> `@Constraint` and `@CrossParameterConstraint`: `@ScriptAssert` is a good candidate
>> Note: how does composition plays into this?
>
> #### Constraint coder class
>
>     @CrossParameterConstraint(validatedBy=CheckRetypedPasswordValidator.class)
>     @interface  CheckRetypedPasswordParameter {
>         String message() default "...";
>         Class<?>[] groups() default {};
>         class<? extends Payload>[] payload();
>     }
>
>     class CheckRetypedPasswordValidator implements
>             CrossParameterConstraintValidator<CheckRetypedPasswordParameter> {
>         ...
>     }
>
> #### User code
>
>     class AccountService {
>         //cross param constraints
>         @CheckRetypedPasswordParameter
>         //return value constraints
>         @Valid @NotNull
>         User createUser(@NotEmpty String username, @Email String email, String password, String retypedPassword);
>     }
>
> ### What is the cross parameter constraint validator contract?
>
> There has been two leading proposals. the others are described in the
> [previous proposal][previous proposal].
>
> #### Generic approach
>
>     interface CrossParameterConstraintValidator<A extends Annotations> {
>         void initialize(...) { ... }
>         boolean isValid(Object[] parameterValues, ConstraintValidatorContext context);
>     }
>
> #### Type-safe approach (with annotation processors)
>
> A more type-safe approach is to reuse the parameters signature of the method to match.
> While the Java compiler cannot discover problems, both an annotation processor and the bean validation provider at runtime
> can detect inconsistent contracts and raise respectively compilation errors and deployment time exception.
>
>     class CheckRetypedPasswordValidator implements
>             CrossParameterConstraintValidator<CheckRetypedPasswordParameter> {
>         void initialize(...) { ... }
>         boolean isValid(String username, String email, String password, String retypedPassword,
>                         ConstraintValidatorContext context) {
>             ...
>         }
>     }
>
> #### Discussions
>
> I think we must put the generic approach in because that's the only way to write non
> method specific cross parameter constraints. Two examples of such constraints are
>
> - script based constraints
> - generic password retype checks based on the parameter indexes
>   `@AreEqual(indexes={2,3}, message="Passwords must be identical")`
>
> So the remaining question is do we also support the type-safe approach in parallel?
> I am inclined to think yes. We can do it on the same `CrossParameterConstraintValidator`
> implementation:
>
>
>     class CheckRetypedPasswordValidator implements
>             CrossParameterConstraintValidator<CheckRetypedPasswordParameter> {
>         void initialize(...) { ... }
>
>         boolean isValid(Object[] parameterValues, ConstraintValidatorContext context);
>
>         boolean isValid(String username, String email, String password, String retypedPassword,
>                         ConstraintValidatorContext context) {
>             ...
>         }
>     }
>
> If the method validated has a matching signature, we use it, otherwise we use the generic
> method.
>

I am inclined to think this can be done as an implementation detail of
a given CPCV.  However, is it intended that multiple CPCV impls might
be enabled for a given CPC type, each presumably handling a different
method signature?  It might actually be simpler in the long run to
promote the type-safe approach such that at most one CPCV with no
typesafe declarations could be enabled.  Perhaps the spec should
provide an abstract TypesafeCrossParameterConstraintValidator that
makes the correct typesafe call.  Perhaps this class could provide a
method to check whether a given signature is supported, or this method
could be specified on the CPCV interface.

> Do we keep the generic `isValid` method on the interface, thus forcing people to implement
> it? Or is that an optional non constrained contract?
> I am tempted to think that forcing is a better approach (the implementation can raise an
> exception). Thoughts?

+1

Matt

>
> [jira]: https://hibernate.onjira.com/browse/BVAL-232
> [previous proposal]: /proposals/BVAL-241/#cross_parameter
>
>
> _______________________________________________
> beanvalidation-dev mailing list
> beanvalidation-dev at lists.jboss.org
> https://lists.jboss.org/mailman/listinfo/beanvalidation-dev


More information about the beanvalidation-dev mailing list