<div dir="ltr">Hey Matt,<div><br></div><div>It's great to see you here, has been a while :)</div><div><br></div><div>Regarding that annotation, could you provide a small example tailored to the issue at hand to show what you have in mind with it? It's not fully clear to me yet.</div><div><br></div><div>Thanks,</div><div><br></div><div>--Gunnar</div><div><br></div><div><br></div></div><div class="gmail_extra"><br><div class="gmail_quote">2016-11-22 21:22 GMT+01:00 Matt Benson <span dir="ltr"><<a href="mailto:mbenson@apache.org" target="_blank">mbenson@apache.org</a>></span>:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">In Therian there is a custom annotation to specify a method that<br>
provides a Type value at runtime. Specifically It allows one to<br>
designate a method that returns an instance of the Typed interface<br>
from Apache Commons Lang 3.x.<br>
<br>
Annotation: <a href="https://github.com/mbenson/therian/blob/master/core/src/main/java/therian/BindTypeVariable.java" rel="noreferrer" target="_blank">https://github.com/mbenson/<wbr>therian/blob/master/core/src/<wbr>main/java/therian/<wbr>BindTypeVariable.java</a><br>
Example: <a href="https://github.com/mbenson/therian/blob/master/core/src/main/java/therian/operation/Transform.java" rel="noreferrer" target="_blank">https://github.com/mbenson/<wbr>therian/blob/master/core/src/<wbr>main/java/therian/operation/<wbr>Transform.java</a><br>
Utilities: <a href="https://github.com/mbenson/therian/blob/master/core/src/main/java/therian/util/Types.java#L88" rel="noreferrer" target="_blank">https://github.com/mbenson/<wbr>therian/blob/master/core/src/<wbr>main/java/therian/util/Types.<wbr>java#L88</a><br>
<br>
An approach like this would of course put some onus onto users with<br>
the payoff of being very explicit. In any case, it might provide food<br>
for thought on the subject.<br>
<br>
Matt<br>
<br>
<br>
On Tue, Nov 22, 2016 at 1:15 PM, Emmanuel Bernard<br>
<div><div class="h5"><<a href="mailto:emmanuel@hibernate.org">emmanuel@hibernate.org</a>> wrote:<br>
><br>
> On 21 Nov 2016, at 14:07, Emmanuel Bernard <<a href="mailto:emmanuel@hibernate.org">emmanuel@hibernate.org</a>> wrote:<br>
><br>
><br>
> On 7 Nov 2016, at 23:42, Hendrik Ebbers <<a href="mailto:hendrik.ebbers@me.com">hendrik.ebbers@me.com</a>> wrote:<br>
><br>
> Let’s say we have the following 2 interfaces:<br>
><br>
> public interface CachedValue<V> {<br>
> V getCachedValue();<br>
> }<br>
><br>
> public interface RealValue<V> {<br>
> V getRealValue();<br>
> }<br>
><br>
> Based on this interfaces we can easily create a new class that implements<br>
> both interfaces:<br>
><br>
> public class CachableValue<V> implements CachedValue<V>, RealValue<V> {<br>
><br>
> private V cachedValue;<br>
><br>
> @Override<br>
> public V getCachedValue() {<br>
> return cachedValue;<br>
> }<br>
><br>
> @Override<br>
> public V getRealValue() {<br>
> V realValue = receiveValueFromServer();<br>
> cachedValue = realValue;<br>
> return realValue;<br>
> }<br>
><br>
> private V receiveValueFromServer() {<br>
> return ServerConnector.<wbr>getCurrentValue(); //Some fake code<br>
> }<br>
> }<br>
><br>
> Let’s try to add a constraint annotation to validate the content of such a<br>
> CachableValue:<br>
><br>
> private CachableValue<@NotEmpty String> myValue;<br>
><br>
> Based on this definition you have absolutely no idea if the @NotEmpty<br>
> annotation is defined for the real value, the cached value or both values.<br>
> From my point of view this is a big problem. Until now its was always easy<br>
> to see how the validation of a model should work based on the validation<br>
> information (annotations) in the model. With this new approach you have no<br>
> idea what will happen.<br>
><br>
> The most simple solution would be to add the support only to some special<br>
> container / wrapper classes like collections, JavaFX properties, etc. I<br>
> think this is a bad idea since new default might come to future versions of<br>
> JavaSE and JavaEE (or maybe Spring) and that won’t be supported. Based on<br>
> this I think that it will be a must to support all wrapper types.<br>
><br>
><br>
> Interesting.<br>
><br>
> I did think about extractors of subtypes but not extractors of parallel<br>
> types.<br>
> I have been thinking about it and explored a few paths:<br>
> - validating all parallel extractors<br>
> - use one<br>
> - validate none<br>
> - fail<br>
><br>
> In the end, I think the cleanest solution is to follow what Ceylon and Java<br>
> do for default methods, they don’t allow ambiguous use and force a<br>
> redefinition.<br>
> <a href="http://stackoverflow.com/questions/16764791/how-does-java-8-new-default-interface-model-works-incl-diamond-multiple-inhe#16788295" rel="noreferrer" target="_blank">http://stackoverflow.com/<wbr>questions/16764791/how-does-<wbr>java-8-new-default-interface-<wbr>model-works-incl-diamond-<wbr>multiple-inhe#16788295</a><br>
><br>
> In practice for us, if there are extractors for CachedValue and for<br>
> RealValue, then CachableValue should fail and require the definition of an<br>
> explicit CachableValue extractor.<br>
> What is interesting in this case is that CachableValue extractor can be see<br>
> as either:<br>
> - a ManyContainerValuesExtractor that will return getCachedValue and<br>
> getRealValue just like a Collection would return get(0) and get(1). This<br>
> approach does not reflect the path difference though<br>
> - or two SingleContainerValueExtractor from the same container type and the<br>
> same value type (*)<br>
><br>
> (*) this is something we do not allow for the moment, we have a unique<br>
> extractor per container + value type. We need to think about how to make<br>
> that work and still allow people to override extractors.<br>
><br>
> So back to your original concern of uncertainty, I think forcing a more<br>
> specific extractor solves the uncertainty that you mentioned. Granted, the<br>
> user would have to know the extractor(s) behavior but in many ways, people<br>
> do need to know about that regardless.<br>
><br>
> Thoughts?<br>
><br>
><br>
> Gunnar and I discussed this problem further and the proposal at large, in<br>
> particular in the light of his alternative proposal (section 3).<br>
><br>
> The main question we have is how common are constraints on user defined type<br>
> like:<br>
><br>
> - CachableValue<V> // CacheableValue<@Email String> value;<br>
> - Tuple<V1,V2> // Tuple<@Email String, @Valid Address> userIdAndAddress;<br>
> - …<br>
><br>
> Here I am excluding:<br>
> - Optional<br>
> - Collection and Map (and all Iterable really)<br>
> - even Collections of non Java languages (Scala, Ceylon, Kotlin if they have<br>
> their own collection type, etc)<br>
><br>
> If constraints on the user defined types described above are common, then we<br>
> need a more systematic solution than imposing to write an extractor for each<br>
> of these cases.<br>
> If they are uncommon and the only containers are Optional, Collection, Map,<br>
> JavaFX containers and other language collections, or more generally<br>
> framework provided containers, then a requiring an extractor implementation<br>
> is not too problematic.<br>
><br>
><br>
> To put some context, the overall BVAL-508 proposal addresses several things:<br>
> - how to extract value from a container<br>
> - where to express constraints on the values of a container<br>
> - how and when the cascading logic should work<br>
><br>
> In my proposal. extractors are explicit implementations (with built-in as<br>
> well as custom implementations). The extractors:<br>
> - extract the value(s)<br>
> - express the link between the extractor and the type parameter (and thus<br>
> the parameterized type)<br>
> - must be implemented explicitly for each tuple extractor / type parameter<br>
><br>
> Gunnar has an alternative proposal or rather a proposal that builds on top<br>
> of the existing one but provide a default generic extractor logic.<br>
><br>
> If no explicit extractor exists, the following will happen<br>
><br>
> Assuming<br>
><br>
> Tuple<@Email String, @Valid Address> userIdAndAddress;<br>
><br>
> class Tuple<V1, V2> {<br>
> V1 v1;<br>
> V2 v2;<br>
><br>
> V1 getV1() { return v1; };<br>
> V2 getV2() { return v2; };<br>
> }<br>
><br>
> The default extractor would look for all getters that return the<br>
> parameterized type(s) and use the getter as extractor. It then would apply<br>
> the constraint.<br>
> In our case, the code would validate getV1() against @Email and getV2() will<br>
> be cascaded.<br>
><br>
> This is elegant and extremely regular. But it has a very ugly angle: should<br>
> we validate the getters or the fields or the getters then the fields?<br>
><br>
> The rule proposed by Gunnar is to validate the getters first because he<br>
> likes them better and then look for fields with no corresponding getter and<br>
> validate them.<br>
><br>
> Assuming<br>
><br>
> Tuple<@Email String, @Valid Address> userIdAndAddress;<br>
><br>
> class Tuple<V1, V2> {<br>
> V1 v1;<br>
> V1 v1b;<br>
> V2 v2;<br>
><br>
> V1 getV1() { return v1; };<br>
> V2 getV2() { return v2; };<br>
> }<br>
><br>
> In this example, the code would validate getV1() against @Email, getV2()<br>
> will be cascaded and v1b will be validated against @Email.<br>
><br>
> This alternative proposal has two advantages:<br>
> - it reduces the number of necessary extractor implementations (assuming the<br>
> relevant elements have getters)<br>
> - it makes the problem described by Hendrik with CacheableValue fully<br>
> deterministic<br>
> - it makes the logic of cascading very regular (for non collection at least)<br>
> - it still requires the ability to write custom extractors for collection<br>
> type containers<br>
><br>
> I have to admit I hate the arbitrary logic of choosing getters and then<br>
> fields.<br>
><br>
> So my questions to you are:<br>
> - how common do you see the Tuple, CacheableValue and other user defined<br>
> type needing validation?<br>
> - would you be satisfied by the getter approach as an extractor?<br>
> - what do you think of the getter priority logic?<br>
><br>
> What do you think?<br>
><br>
> Emmanuel<br>
><br>
</div></div>> ______________________________<wbr>_________________<br>
> beanvalidation-dev mailing list<br>
> <a href="mailto:beanvalidation-dev@lists.jboss.org">beanvalidation-dev@lists.<wbr>jboss.org</a><br>
> <a href="https://lists.jboss.org/mailman/listinfo/beanvalidation-dev" rel="noreferrer" target="_blank">https://lists.jboss.org/<wbr>mailman/listinfo/<wbr>beanvalidation-dev</a><br>
<br>
______________________________<wbr>_________________<br>
beanvalidation-dev mailing list<br>
<a href="mailto:beanvalidation-dev@lists.jboss.org">beanvalidation-dev@lists.<wbr>jboss.org</a><br>
<a href="https://lists.jboss.org/mailman/listinfo/beanvalidation-dev" rel="noreferrer" target="_blank">https://lists.jboss.org/<wbr>mailman/listinfo/<wbr>beanvalidation-dev</a></blockquote></div><br></div>