<html><head><meta http-equiv="Content-Type" content="text/html charset=utf-8"></head><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class="">I’ve created a blog post and survey on the subject<div class=""><a href="http://beanvalidation.org/news/2016/11/23/survey-constraints-and-parameterized-type/" class="">http://beanvalidation.org/news/2016/11/23/survey-constraints-and-parameterized-type/</a></div><div class=""><br class=""></div><div class="">Tweet, share and spread around the world :)</div><div class=""><br class=""></div><div class="">Emmanuel</div><div class=""><br class=""><div><blockquote type="cite" class=""><div class="">On 22 Nov 2016, at 20:15, Emmanuel Bernard &lt;<a href="mailto:emmanuel@hibernate.org" class="">emmanuel@hibernate.org</a>&gt; wrote:</div><br class="Apple-interchange-newline"><div class=""><meta http-equiv="Content-Type" content="text/html charset=utf-8" class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><br class=""><div class=""><blockquote type="cite" class=""><div class="">On 21 Nov 2016, at 14:07, Emmanuel Bernard &lt;<a href="mailto:emmanuel@hibernate.org" class="">emmanuel@hibernate.org</a>&gt; wrote:</div><br class="Apple-interchange-newline"><div class=""><meta http-equiv="Content-Type" content="text/html charset=utf-8" class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><br class=""><div class=""><blockquote type="cite" class=""><div class="">On 7 Nov 2016, at 23:42, Hendrik Ebbers &lt;<a href="mailto:hendrik.ebbers@me.com" class="">hendrik.ebbers@me.com</a>&gt; wrote:</div><div class=""><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space;" class=""><br class="">Let’s say we have the following 2 interfaces:<br class=""><br class=""><font face="Courier New" class="">public interface&nbsp;CachedValue&lt;V&gt; {<br class="">&nbsp; &nbsp;&nbsp;V getCachedValue();<br class="">}<br class=""><br class="">public interface&nbsp;RealValue&lt;V&gt; {<br class="">&nbsp; &nbsp;&nbsp;V getRealValue();<br class="">}</font><br class=""><br class="">Based on this interfaces we can easily create a new class that implements both interfaces:<br class=""><br class=""><font face="Courier New" class="">public class&nbsp;CachableValue&lt;V&gt;&nbsp;implements&nbsp;CachedValue&lt;V&gt;, RealValue&lt;V&gt; {<br class=""><br class="">&nbsp; &nbsp;&nbsp;private&nbsp;V&nbsp;cachedValue;<br class=""><br class="">&nbsp; &nbsp;&nbsp;@Override<br class="">&nbsp; &nbsp;&nbsp;public&nbsp;V getCachedValue() {<br class="">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return cachedValue;<br class="">&nbsp; &nbsp;&nbsp;}<br class=""><br class="">&nbsp; &nbsp;&nbsp;@Override<br class="">&nbsp; &nbsp;&nbsp;public&nbsp;V getRealValue() {<br class="">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;V realValue = receiveValueFromServer();<br class="">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;cachedValue&nbsp;= realValue;<br class="">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return&nbsp;realValue;<br class="">&nbsp; &nbsp;&nbsp;}<br class=""><br class="">&nbsp; &nbsp;&nbsp;private&nbsp;V receiveValueFromServer() {<br class="">&nbsp; &nbsp; &nbsp; &nbsp;&nbsp;return ServerConnector.getCurrentValue(); //Some fake code<br class="">&nbsp; &nbsp;&nbsp;}<br class="">}</font><br class=""><br class="">Let’s try to add a constraint annotation to validate the content of such a CachableValue:<br class=""><br class=""><font face="Courier New" class="">private&nbsp;CachableValue&lt;@NotEmpty String&gt;&nbsp;myValue;</font><br class=""><br class="">Based on this definition you have absolutely no idea if the @NotEmpty annotation is defined for the real value, the cached value or both values. From my point of view this is a big problem.&nbsp;Until now its was always easy to see how the validation of a model should work based on the validation information (annotations) in the model. With this new approach you have no idea&nbsp;what will happen.<br class=""><br class="">The most simple solution would be to add the support only to some special container / wrapper classes like collections, JavaFX properties, etc. I think this is a bad idea since new default&nbsp;might come to future versions of JavaSE and JavaEE (or maybe Spring) and that won’t be supported. Based on this I think that it will be a must to support all wrapper types.&nbsp;<br class=""></div></div></blockquote></div><br class=""><div class="">Interesting.</div><div class=""><br class=""></div><div class="">I did think about extractors of subtypes but not extractors of parallel types.</div><div class="">I have been thinking about it and explored a few paths:</div><div class="">- validating all parallel extractors</div><div class="">- use one</div><div class="">- validate none</div><div class="">- fail</div><div class=""><br class=""></div><div class="">In the end, I think the cleanest solution is to follow what Ceylon and Java do for default methods, they don’t allow ambiguous use and force a redefinition.</div><div class=""><a href="http://stackoverflow.com/questions/16764791/how-does-java-8-new-default-interface-model-works-incl-diamond-multiple-inhe#16788295" class="">http://stackoverflow.com/questions/16764791/how-does-java-8-new-default-interface-model-works-incl-diamond-multiple-inhe#16788295</a></div><div class=""><br class=""></div><div class="">In practice for us, if&nbsp;there are extractors for&nbsp;CachedValue and for&nbsp;RealValue, then CachableValue should fail and require the definition of an explicit&nbsp;CachableValue extractor.</div><div class="">What is interesting in this case is that&nbsp;CachableValue extractor can be see as either:</div><div class="">- a&nbsp;ManyContainerValuesExtractor that will return getCachedValue and getRealValue just like a Collection would return get(0) and get(1). This approach does not reflect the path difference though</div><div class="">- or two SingleContainerValueExtractor from the same container type and the same value type (*)</div><div class=""><br class=""></div><div class="">(*) this is something we do not allow for the moment, we have a unique extractor per container + value type. We need to think about how to make that work and still allow people to override extractors.</div><div class=""><br class=""></div><div class="">So back to your original concern of uncertainty, I think forcing a more specific extractor solves the uncertainty that you mentioned. Granted, the user would have to know the extractor(s) behavior but in many ways, people do need to know about that regardless.</div><div class=""><br class=""></div><div class="">Thoughts?</div></div></div></blockquote><br class=""></div><div class="">Gunnar and I discussed this problem further and the proposal at large, in particular in the light of his alternative proposal (section 3).</div><div class=""><br class=""></div><div class="">The main question we have is how common are constraints on user defined type like:</div><div class=""><br class=""></div><div class="">-&nbsp;CachableValue&lt;V&gt; // CacheableValue&lt;@Email String&gt; value;</div><div class="">- Tuple&lt;V1,V2&gt; // Tuple&lt;@Email String, @Valid Address&gt; userIdAndAddress;</div><div class="">- …</div><div class=""><br class=""></div><div class="">Here I am excluding:</div><div class="">- Optional</div><div class="">- Collection and Map (and all Iterable really)</div><div class="">- even Collections of non Java languages (Scala, Ceylon, Kotlin if they have their own collection type, etc)</div><div class=""><br class=""></div><div class="">If constraints on the user defined types described above are common, then we need a more systematic solution than imposing to write an extractor for each of these cases.</div><div class="">If they are uncommon and the only containers are Optional, Collection, Map, JavaFX containers and other language collections, or more generally framework provided containers, then a requiring an extractor implementation is not too problematic.</div><div class=""><br class=""></div><div class=""><br class=""></div><div class="">To put some context, the overall BVAL-508 proposal addresses several things:</div><div class="">- how to extract value from a container</div><div class="">- where to express constraints on the values of a container</div><div class="">- how and when the cascading logic should work</div><div class=""><br class=""></div><div class="">In my proposal. extractors are explicit implementations (with built-in as well as custom implementations). The extractors:</div><div class="">- extract the value(s)</div><div class="">- express the link between the extractor and the type parameter (and thus the parameterized type)</div><div class="">- must be implemented explicitly for each tuple extractor / type parameter</div><div class=""><br class=""></div><div class="">Gunnar has an alternative proposal or rather a proposal that builds on top of the existing one but provide a default generic extractor logic.</div><div class=""><br class=""></div><div class="">If no explicit extractor exists, the following will happen</div><div class=""><br class=""></div><div class="">Assuming&nbsp;</div><div class=""><br class=""></div><div class="">Tuple&lt;@Email String, @Valid Address&gt; userIdAndAddress;</div><div class=""><br class=""></div><div class="">class Tuple&lt;V1, V2&gt; {</div><div class="">&nbsp; &nbsp; V1 v1;</div><div class="">&nbsp; &nbsp; V2 v2;</div><div class=""><br class=""></div><div class="">&nbsp; &nbsp; V1 getV1() { return v1; };</div><div class="">&nbsp; &nbsp; V2 getV2() { return v2; };</div><div class="">}</div><div class=""><br class=""></div>The default extractor would look for all getters that return the parameterized type(s) and use the getter as extractor. It then would apply the constraint.<div class="">In our case, the code would validate getV1() against @Email and getV2() will be cascaded.</div><div class=""><br class=""></div><div class="">This is elegant and extremely regular. But it has a very ugly angle: should we validate the getters or the fields or the getters then the fields?</div><div class=""><br class=""></div><div class="">The rule proposed by Gunnar is to validate the getters first because he likes them better and then look for fields with no corresponding getter and validate them.</div><div class=""><br class=""></div><div class=""><div class="">Assuming&nbsp;</div><div class=""><br class=""></div><div class="">Tuple&lt;@Email String, @Valid Address&gt; userIdAndAddress;</div><div class=""><br class=""></div><div class="">class Tuple&lt;V1, V2&gt; {</div><div class="">&nbsp; &nbsp; V1 v1;</div><div class="">&nbsp; &nbsp; V1 v1b;</div><div class="">&nbsp; &nbsp; V2 v2;</div><div class=""><br class=""></div><div class="">&nbsp; &nbsp; V1 getV1() { return v1; };</div><div class="">&nbsp; &nbsp; V2 getV2() { return v2; };</div><div class="">}</div></div><div class=""><br class=""></div><div class="">In this example, the code would validate getV1() against @Email, getV2() will be cascaded and v1b will be validated against @Email.</div><div class=""><br class=""></div><div class="">This alternative proposal has two advantages:</div><div class="">- it reduces the number of necessary extractor implementations (assuming the relevant elements have getters)</div><div class="">- it makes the problem described by Hendrik with CacheableValue fully deterministic</div><div class="">- it makes the logic of cascading very regular (for non collection at least)</div><div class="">- it still requires the ability to write custom extractors for collection type containers</div><div class=""><br class=""></div><div class="">I have to admit I hate the arbitrary logic of choosing getters and then fields.</div><div class=""><br class=""></div><div class="">So my questions to you are:</div><div class="">- how common do you see the Tuple, CacheableValue and other user defined type needing validation?</div><div class="">- would you be satisfied by the getter approach as an extractor?</div><div class="">- what do you think of the getter priority logic?</div><div class=""><br class=""></div><div class="">What do you think?</div><div class=""><br class=""></div><div class="">Emmanuel</div></div>_______________________________________________<br class="">beanvalidation-dev mailing list<br class=""><a href="mailto:beanvalidation-dev@lists.jboss.org" class="">beanvalidation-dev@lists.jboss.org</a><br class="">https://lists.jboss.org/mailman/listinfo/beanvalidation-dev</div></blockquote></div><br class=""></div></body></html>