Hi<div><br></div><div>I have very few concerns with the generic approach, I can&#39;t see why it couldn&#39;t be stable for some time, we can provide it now and it should cover all use cases albeit without type safety? It&#39;s the type safe approach I&#39;d have more concerns about a future spec. wanting to update and finding itself hamstrung by a decision now, perhaps it is biting off more than a JSR should. Happy to be persuaded otherwise though.</div>
<div><br></div><div>Another +1 for not validating parameters and return values in a single constraint.</div><div><br></div><div>Regards</div><div>Rich</div><div><br><br><div class="gmail_quote">On 1 September 2012 17:38, Gunnar Morling <span dir="ltr">&lt;<a href="mailto:gunnar@hibernate.org" target="_blank">gunnar@hibernate.org</a>&gt;</span> wrote:<br>
<blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">Hi,<br>
<br>
Based on our discussions around the issue, I&#39;m wondering whether we<br>
should put cross-parameter validation into BV 1.1 at all.<br>
<br>
AFAIK none of the BV implementations provides such a feature, so with<br>
this we&#39;d be pretty much on the &quot;innovating things&quot; side of what a JSR<br>
can do, opposed to the &quot;standardization&quot; side of the spectrum. IMO it<br>
would be better to see cross-parameter validation be implemented by at<br>
least one BV provider to gather some experiences and then standardize.<br>
<br>
Note that a user can work around the lack of cross-parameter<br>
validation by pulling the concerned parameters into a parameter<br>
object, putting a class-level constraint on it and annotating the<br>
parameter with @Valid.<br>
<br>
If we really want to add this to BV 1.1, IMO we should only add the<br>
generic approach and let implementors experiment with the type-safe<br>
one.<br>
<br>
&gt; 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.<br>
<br>
Wouldn&#39;t this contradict the idea of type-safety? If the validated<br>
method signature gets changed without adapting the validator, silently<br>
the generic method would be used, and also an annotation processor<br>
couldn&#39;t raise an error since there is the generic method.<br>
<br>
Thinking more about it, I&#39;m wondering how we would represent<br>
cross-parameter constraints in ConstraintViolations. What should be<br>
returned by getInvalidValue()/getLeafBean()? getPropertyPath() might<br>
be an issue, too. For single parameters we have one node representing<br>
the concerned parameter at the end of the violation&#39;s path, but this<br>
wouldn&#39;t work here. Perhaps the path could just end with the method<br>
node in that case.<br>
<br>
Thoughts?<br>
<br>
--Gunnar<br>
<br>
<br>
2012/8/29 Matt Benson &lt;<a href="mailto:mbenson@apache.org">mbenson@apache.org</a>&gt;:<br>
<div class="HOEnZb"><div class="h5">&gt; On Wed, Aug 29, 2012 at 4:03 AM, Emmanuel Bernard<br>
&gt; &lt;<a href="mailto:emmanuel@hibernate.org">emmanuel@hibernate.org</a>&gt; wrote:<br>
&gt;&gt; I would like to bring home cross parameter validation which is one of the main open issues in method validation.<br>
&gt;&gt; We have been discussing it for literally 11 months, it&#39;s time to converge. If you could give your feedback quickly, Gunnar<br>
&gt;&gt; might be able to add it to the spec in the next few days. I am already pushing him harder than I should to<br>
&gt;&gt; move BV forward so give him some help :)<br>
&gt;&gt;<br>
&gt;&gt; The following is a less readable copy of what you can find at <a href="http://beanvalidation.org/proposals/BVAL-232/" target="_blank">http://beanvalidation.org/proposals/BVAL-232/</a><br>
&gt;&gt;<br>
&gt;&gt; ### Cross parameter validation and return value<br>
&gt;&gt;<br>
&gt;&gt; Do we agree that validating both the parameters and the return value in a single<br>
&gt;&gt; constraint validator is not a use case we want to cover?<br>
&gt;&gt; To me that would be awkward to support it as we would need to execute the method<br>
&gt;&gt; to validate it.<br>
&gt;&gt;<br>
&gt;<br>
&gt; +1, yet nothing should be done to preclude adding this in a later<br>
&gt; version of the spec.<br>
&gt;<br>
&gt;&gt; ### Where to host cross-parameter constraints<br>
&gt;&gt;<br>
&gt;&gt; We use the method as host to the return value constraints and possibly `@Valid`.<br>
&gt;&gt; That is unfortunately also the natural place for cross parameter constraints.<br>
&gt;&gt;<br>
&gt;&gt; I cannot think of another place to put them. There is also no easy way to add a<br>
&gt;&gt; visual cue and differentiate a regular constraint from a cross param constraint<br>
&gt;&gt; except by its meta annotation. We would rely on the user adding a visual cue in<br>
&gt;&gt; the constraint name. Which kind of cue? Put `param` in the constraint name?<br>
&gt;<br>
&gt; In the end this is not something that should be enforced anyway, so I<br>
&gt; suspect far too much thought has been given to it already.  ;)  Using<br>
&gt; the CheckRetypedPasswordParameter example, I would personally prefer<br>
&gt; CheckRetypedPasswordParams and extrapolate that to &quot;ends with<br>
&gt; &#39;Params&#39;&quot;.  Find an example or two everyone is comfortable with,<br>
&gt; extrapolate a *recommendation* as in the example of .@List for<br>
&gt; multiple constraints and move on.  :)<br>
&gt;<br>
&gt;&gt;<br>
&gt;&gt; Any one can think of a better approach?<br>
&gt;<br>
&gt; Nothing from me.<br>
&gt;<br>
&gt;&gt;<br>
&gt;&gt; #### Bean Validation class<br>
&gt;&gt;<br>
&gt;&gt;     @interface CrossParameterConstraint {<br>
&gt;&gt;         public Class&lt;? extends CrossParameterConstraintValidator&lt;?, ?&gt;&gt;[] validatedBy();<br>
&gt;&gt;     }<br>
&gt;<br>
&gt; Why &lt;?, ?&gt; on the CPCV signature?  I assume this is an error as it&#39;s<br>
&gt; not consistent with the CheckRetypedPasswordValidator example below.<br>
&gt;<br>
&gt;&gt;<br>
&gt;&gt;     interface CrossParameterConstraintValidator&lt;A extends Annotation&gt; {<br>
&gt;&gt;         void initialize(A constraintAnnotation);<br>
&gt;&gt;         [...]<br>
&gt;&gt;     }<br>
&gt;&gt;<br>
&gt;&gt;&gt; Question: does these different annotations/interfaces affect the metadata API?<br>
&gt;<br>
&gt; I haven&#39;t looked at the metadata API in depth where it applies to<br>
&gt; method validation, but it might be nice to differentiate<br>
&gt; cross-parameter constraints from return value constraints at the<br>
&gt; metadata level to save users the trouble.<br>
&gt;<br>
&gt;&gt;&gt;<br>
&gt;&gt;&gt; Question: can the same constraint annotation be annotated by both<br>
&gt;&gt;&gt; `@Constraint` and `@CrossParameterConstraint`: `@ScriptAssert` is a good candidate<br>
&gt;&gt;&gt; Note: how does composition plays into this?<br>
&gt;&gt;<br>
&gt;&gt; #### Constraint coder class<br>
&gt;&gt;<br>
&gt;&gt;     @CrossParameterConstraint(validatedBy=CheckRetypedPasswordValidator.class)<br>
&gt;&gt;     @interface  CheckRetypedPasswordParameter {<br>
&gt;&gt;         String message() default &quot;...&quot;;<br>
&gt;&gt;         Class&lt;?&gt;[] groups() default {};<br>
&gt;&gt;         class&lt;? extends Payload&gt;[] payload();<br>
&gt;&gt;     }<br>
&gt;&gt;<br>
&gt;&gt;     class CheckRetypedPasswordValidator implements<br>
&gt;&gt;             CrossParameterConstraintValidator&lt;CheckRetypedPasswordParameter&gt; {<br>
&gt;&gt;         ...<br>
&gt;&gt;     }<br>
&gt;&gt;<br>
&gt;&gt; #### User code<br>
&gt;&gt;<br>
&gt;&gt;     class AccountService {<br>
&gt;&gt;         //cross param constraints<br>
&gt;&gt;         @CheckRetypedPasswordParameter<br>
&gt;&gt;         //return value constraints<br>
&gt;&gt;         @Valid @NotNull<br>
&gt;&gt;         User createUser(@NotEmpty String username, @Email String email, String password, String retypedPassword);<br>
&gt;&gt;     }<br>
&gt;&gt;<br>
&gt;&gt; ### What is the cross parameter constraint validator contract?<br>
&gt;&gt;<br>
&gt;&gt; There has been two leading proposals. the others are described in the<br>
&gt;&gt; [previous proposal][previous proposal].<br>
&gt;&gt;<br>
&gt;&gt; #### Generic approach<br>
&gt;&gt;<br>
&gt;&gt;     interface CrossParameterConstraintValidator&lt;A extends Annotations&gt; {<br>
&gt;&gt;         void initialize(...) { ... }<br>
&gt;&gt;         boolean isValid(Object[] parameterValues, ConstraintValidatorContext context);<br>
&gt;&gt;     }<br>
&gt;&gt;<br>
&gt;&gt; #### Type-safe approach (with annotation processors)<br>
&gt;&gt;<br>
&gt;&gt; A more type-safe approach is to reuse the parameters signature of the method to match.<br>
&gt;&gt; While the Java compiler cannot discover problems, both an annotation processor and the bean validation provider at runtime<br>
&gt;&gt; can detect inconsistent contracts and raise respectively compilation errors and deployment time exception.<br>
&gt;&gt;<br>
&gt;&gt;     class CheckRetypedPasswordValidator implements<br>
&gt;&gt;             CrossParameterConstraintValidator&lt;CheckRetypedPasswordParameter&gt; {<br>
&gt;&gt;         void initialize(...) { ... }<br>
&gt;&gt;         boolean isValid(String username, String email, String password, String retypedPassword,<br>
&gt;&gt;                         ConstraintValidatorContext context) {<br>
&gt;&gt;             ...<br>
&gt;&gt;         }<br>
&gt;&gt;     }<br>
&gt;&gt;<br>
&gt;&gt; #### Discussions<br>
&gt;&gt;<br>
&gt;&gt; I think we must put the generic approach in because that&#39;s the only way to write non<br>
&gt;&gt; method specific cross parameter constraints. Two examples of such constraints are<br>
&gt;&gt;<br>
&gt;&gt; - script based constraints<br>
&gt;&gt; - generic password retype checks based on the parameter indexes<br>
&gt;&gt;   `@AreEqual(indexes={2,3}, message=&quot;Passwords must be identical&quot;)`<br>
&gt;&gt;<br>
&gt;&gt; So the remaining question is do we also support the type-safe approach in parallel?<br>
&gt;&gt; I am inclined to think yes. We can do it on the same `CrossParameterConstraintValidator`<br>
&gt;&gt; implementation:<br>
&gt;&gt;<br>
&gt;&gt;<br>
&gt;&gt;     class CheckRetypedPasswordValidator implements<br>
&gt;&gt;             CrossParameterConstraintValidator&lt;CheckRetypedPasswordParameter&gt; {<br>
&gt;&gt;         void initialize(...) { ... }<br>
&gt;&gt;<br>
&gt;&gt;         boolean isValid(Object[] parameterValues, ConstraintValidatorContext context);<br>
&gt;&gt;<br>
&gt;&gt;         boolean isValid(String username, String email, String password, String retypedPassword,<br>
&gt;&gt;                         ConstraintValidatorContext context) {<br>
&gt;&gt;             ...<br>
&gt;&gt;         }<br>
&gt;&gt;     }<br>
&gt;&gt;<br>
&gt;&gt; If the method validated has a matching signature, we use it, otherwise we use the generic<br>
&gt;&gt; method.<br>
&gt;&gt;<br>
&gt;<br>
&gt; I am inclined to think this can be done as an implementation detail of<br>
&gt; a given CPCV.  However, is it intended that multiple CPCV impls might<br>
&gt; be enabled for a given CPC type, each presumably handling a different<br>
&gt; method signature?  It might actually be simpler in the long run to<br>
&gt; promote the type-safe approach such that at most one CPCV with no<br>
&gt; typesafe declarations could be enabled.  Perhaps the spec should<br>
&gt; provide an abstract TypesafeCrossParameterConstraintValidator that<br>
&gt; makes the correct typesafe call.  Perhaps this class could provide a<br>
&gt; method to check whether a given signature is supported, or this method<br>
&gt; could be specified on the CPCV interface.<br>
&gt;<br>
&gt;&gt; Do we keep the generic `isValid` method on the interface, thus forcing people to implement<br>
&gt;&gt; it? Or is that an optional non constrained contract?<br>
&gt;&gt; I am tempted to think that forcing is a better approach (the implementation can raise an<br>
&gt;&gt; exception). Thoughts?<br>
&gt;<br>
&gt; +1<br>
&gt;<br>
&gt; Matt<br>
&gt;<br>
&gt;&gt;<br>
&gt;&gt; [jira]: <a href="https://hibernate.onjira.com/browse/BVAL-232" target="_blank">https://hibernate.onjira.com/browse/BVAL-232</a><br>
&gt;&gt; [previous proposal]: /proposals/BVAL-241/#cross_parameter<br>
&gt;&gt;<br>
&gt;&gt;<br>
&gt;&gt; _______________________________________________<br>
&gt;&gt; beanvalidation-dev mailing list<br>
&gt;&gt; <a href="mailto:beanvalidation-dev@lists.jboss.org">beanvalidation-dev@lists.jboss.org</a><br>
&gt;&gt; <a href="https://lists.jboss.org/mailman/listinfo/beanvalidation-dev" target="_blank">https://lists.jboss.org/mailman/listinfo/beanvalidation-dev</a><br>
&gt; _______________________________________________<br>
&gt; beanvalidation-dev mailing list<br>
&gt; <a href="mailto:beanvalidation-dev@lists.jboss.org">beanvalidation-dev@lists.jboss.org</a><br>
&gt; <a href="https://lists.jboss.org/mailman/listinfo/beanvalidation-dev" target="_blank">https://lists.jboss.org/mailman/listinfo/beanvalidation-dev</a><br>
_______________________________________________<br>
beanvalidation-dev mailing list<br>
<a href="mailto:beanvalidation-dev@lists.jboss.org">beanvalidation-dev@lists.jboss.org</a><br>
<a href="https://lists.jboss.org/mailman/listinfo/beanvalidation-dev" target="_blank">https://lists.jboss.org/mailman/listinfo/beanvalidation-dev</a><br>
</div></div></blockquote></div><br></div>