[bv-dev] Cross parameter validation convergence
Gunnar Morling
gunnar at hibernate.org
Sat Sep 1 12:38:58 EDT 2012
Hi,
Based on our discussions around the issue, I'm wondering whether we
should put cross-parameter validation into BV 1.1 at all.
AFAIK none of the BV implementations provides such a feature, so with
this we'd be pretty much on the "innovating things" side of what a JSR
can do, opposed to the "standardization" side of the spectrum. IMO it
would be better to see cross-parameter validation be implemented by at
least one BV provider to gather some experiences and then standardize.
Note that a user can work around the lack of cross-parameter
validation by pulling the concerned parameters into a parameter
object, putting a class-level constraint on it and annotating the
parameter with @Valid.
If we really want to add this to BV 1.1, IMO we should only add the
generic approach and let implementors experiment with the type-safe
one.
> We can do it on the same CrossParameterConstraintValidator implementation [...] If the method validated has a matching signature, we use it, otherwise we use the generic method.
Wouldn't this contradict the idea of type-safety? If the validated
method signature gets changed without adapting the validator, silently
the generic method would be used, and also an annotation processor
couldn't raise an error since there is the generic method.
Thinking more about it, I'm wondering how we would represent
cross-parameter constraints in ConstraintViolations. What should be
returned by getInvalidValue()/getLeafBean()? getPropertyPath() might
be an issue, too. For single parameters we have one node representing
the concerned parameter at the end of the violation's path, but this
wouldn't work here. Perhaps the path could just end with the method
node in that case.
Thoughts?
--Gunnar
2012/8/29 Matt Benson <mbenson at apache.org>:
> 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
> _______________________________________________
> 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