<div dir="ltr"><div><div><div><div><div>Hi,<br><br></div><div>We would like to discuss with you the node structure of the ConstraintViolation path in the case of value extraction (2 cases really: cascaded validation and type argument constraints).<br></div><div><br></div>This is not an easy one! And we will also digress on the string representation while we&#39;re at it even if it&#39;s not part of the spec.<br><br></div><div>= 1. Type parameter information<br></div><div><br></div>== 1.1 Should we add the type parameter to the node?<br><br></div>Assume the example of a map:<br></div>private Map&lt;@Valid City (1), @Valid Statistics (2)&gt; map;<br><br></div><div>With the current way of doing things, you end up with the following paths:<br></div><div><div><div><div><div><div><div>(1) (name = map, type = PROPERTY) -&gt; (name = name, type = PROPERTY, isInIterable = true, key = city)<br></div><div>(2) (name = map, type = PROPERTY) -&gt; (name = count, type = PROPERTY, isInIterable = true, key = city)<br></div><div><br></div><div>So you wouldn&#39;t be able to differentiate if the violations is coming from City or Statistics.<br><br></div><div>One of the ideas we had is to integrate the TypeVariable&lt;?&gt; type parameter info into the last node. In the case of (1), you would have 2 nodes:<br></div><div>(1) (name = map, type = PROPERTY) -&gt; (name = name, type = PROPERTY, isInIterable = true, key = city, typeParameter = K)<br></div><div>(2) (name = map, type = PROPERTY) -&gt; (name = count, type = PROPERTY, isInIterable = true, key = city, typeParameter = V)<br><br></div><div>WDYT?<br></div><div><br></div><div>== 1.2 If we add this information, what should it be?<br><br></div><div>At first, Gunnar thought about using java.lang.reflect.TypeVariable for this type parameter information but we have an issue with it: it is not serializable and the path is supposed to be.<br><br></div><div>Thus we need to either use a String with the name of the type parameter or introduce our own serializable structure.<br><br></div><div>What&#39;s your take on this? If we go the structure route, which information should this structure contain apart from the name? java.lang.reflect.TypeVariable also has the generic declaration information.<br><br></div><div>Do you foresee issues if we are not using java.lang.reflect.TypeVariable? Typically it would be harder to do additional reflection things.<br><br></div><div>= 2. Type argument constraints<br><br></div><div>So, the discussion above also applies to type argument constraints but there are some specific questions for them.<br></div><div><br></div><div>== 2.1 New node type<br><br><div>Type argument constraints cover the following case, ZipCode being a constraint:<br></div>Map&lt;@ZipCode String, String&gt; map;</div><div><br></div><div>In this case, we envision the following node structure (assuming we would add the typeParameter discussed in 1.1):<br></div><div>(name = map, type = property) -&gt; (name = &#39;&lt;map key&gt;&#39;, type = TYPE_ARGUMENT, isInIterable = true, key = myKey, typeParameter = K)<br><br></div><div>TYPE_ARGUMENT is a new type introduced in javax.validation.ElementKind.<br><br></div><div>Does it make sense?<br></div><div><br></div><div>== 2.2 Default node names<br><br></div><div>The default extractors define the following node names for the added TYPE_ARGUMENT node:<br></div><div>- arrays and Iterables (List included): &lt;iterable element&gt;<br></div><div>- Map key: &lt;map key&gt;<br></div><div>- Map value: &lt;map value&gt;<br><br></div><div>This is similar to the nodes we created for &quot;&lt;return value&gt;&quot; or &quot;&lt;cross-parameter&gt;&quot; constraints.<br><br></div><div>Question: should they have a node name? should it be the type parameter name instead (so E or K or V for instance)?<br></div><div><br></div><div>Note that this might have consequences in the string representation we will discuss later.<br></div><div><br></div><div>== 2.3 Optional and ObservableValue<br><br></div><div>In these 2 cases, we won&#39;t append a node.<br><br></div><div>Note that while in the ObservableValue case, it might feel more natural as the constraint will probably be used like:<br></div><div>@NotBlank StringProperty property;<br></div><div>to apply a NotBlank constraint on the wrapped value so it&#39;s rather logical to not have a node.<br><br></div><div>Just to be clear, for Optional, on the other hand, with our proposal, we won&#39;t have a node whereas the code looks like:<br></div><div>Optional&lt;@NotBlank String&gt; optional;<br></div><div><br></div><div>= 3 String representation<br><br></div><div>Note: this is implementation specific but we thought it might be interesting to discuss it here anyway.<br><br></div><div>The Path toString() is included in ConstraintViolationException.getMessage().<br></div><div><br></div><div>If we consider what we proposed above and the following property:<br>Map&lt;@NotNull @Valid Address, String&gt; nicksByAddress;<br><br></div><div>We would end up with:<br>map&lt;K&gt;[address.toString()].street //error in address.street<br>map&lt;K&gt;[address.toString()].&lt;map key&gt; //error in type param of address<br>map&lt;K&gt;[address.toString()] //error in class level address - there is a bean node which we don&#39;t show<br><br></div><div>If we consider the following property:<br>Map&lt;String, @NotNull @Valid Address&gt; addressesByNick;<br><br></div><div>And we decided to be consistent with the fact that we add the type parameter information, we would end up with:<br>map&lt;V&gt;[address.toString()].street //error in address.street<br>map&lt;V&gt;[address.toString()].&lt;map key&gt; //error in type param of address<br>map&lt;V&gt;[address.toString()] //error in class level address - there is a bean node which we don&#39;t show</div><div><br></div><div>Note that this breaks the previous behavior of HV 5.x as we used to only support constraints on the value and we did not have the &#39;&lt;V&gt;&#39; information.<br><br></div><div>The issue becomes a bit more pregnant in the case of Lists. Let&#39;s assume we have the following property:<br></div><div>List&lt;@NotNull @Valid Address&gt; addresses;<br><br></div><div>We would end up with:<br></div><div>addresses&lt;E&gt;[0].street //error in address.street</div><div>addresses&lt;E&gt;[0].&lt;iterable element&gt; //error in type param of address</div><div>addresses&lt;E&gt;[0] //error in class level address - there is a bean node which we don&#39;t show<br><br></div><div>Question that becomes obvious here: if it were possible to only display the type parameter if we have &gt; 1 type parameters in the original generic declaration, would it make sense to omit it? Basically, we have to discuss consistency vs readability.<br><br></div><div>To completely illustrate the discussion, let&#39;s take a look at what happens with nested type argument constraints (it is not in the spec yet but we experimented with it in HV - we&#39;ll discuss this in a future email):<br></div><div>Map&lt;String, List&lt;@NotNull @Valid Address&gt;&gt; listOfAddressesByNick;<br><br></div><div>In this case, the envisioned string representation would be:<br>listOfAddressesByNick&lt;V&gt;[myKey].&lt;map value&gt;&lt;E&gt;[0].street //error in address.street<br>listOfAddressesByNick&lt;V&gt;[myKey].&lt;map value&gt;&lt;E&gt;[0].&lt;iterable element&gt; //error in type param of address<br>listOfAddressesByNick&lt;V&gt;[myKey].&lt;map value&gt;&lt;E&gt;[0] //error in class level address - there is a bean node which we don&#39;t show<br><br></div><div>So, as you can see, the readability can become an issue.<br><br></div><div>Thoughts? Ideas?<br><br>-- <br></div><div>Guillaume<br></div></div></div></div></div></div></div></div>