<html><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space; ">Please review and comment.<br><div><br><div>Begin forwarded message:</div><br class="Apple-interchange-newline"><blockquote type="cite"><div><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; "><font face="Helvetica" size="3" color="#000000" style="font: 12.0px Helvetica; color: #000000"><b>From: </b></font><font face="Helvetica" size="3" style="font: 12.0px Helvetica">Emmanuel Bernard &lt;<a href="mailto:emmanuel.bernard@jboss.com">emmanuel.bernard@jboss.com</a>&gt;</font></div><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; "><font face="Helvetica" size="3" color="#000000" style="font: 12.0px Helvetica; color: #000000"><b>Date:<span class="Apple-converted-space">&nbsp;</span></b></font><font face="Helvetica" size="3" style="font: 12.0px Helvetica"> June 17, 2009 14:41:03<span class="Apple-converted-space">&nbsp; </span>EDT</font></div><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; "><font face="Helvetica" size="3" color="#000000" style="font: 12.0px Helvetica; color: #000000"><b>To:&nbsp;</b></font></div><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; "><font face="Helvetica" size="3" color="#000000" style="font: 12.0px Helvetica; color: #000000"><b>Subject: </b></font><font face="Helvetica" size="3" style="font: 12.0px Helvetica"><b>Re: Path, string or object model</b></font></div><div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; min-height: 14px; "><br></div> </div><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space; ">Here is the solution I cooked. I think it's acceptable but add some complexity in the ConstraintValidatorContext API (see other email). Please review (pay special attention to the examples).<div><br></div><div>A Path represents the path and is the one accepted by the path consuming APIs. A Path is an&nbsp;Iterable&nbsp;of&nbsp;Nodes.</div><div><br></div><div><div>/**</div><div>&nbsp;* Represent a navigation path from an object to another.</div><div>&nbsp;* Each path element is represented by a Node.</div><div>&nbsp;*</div><div>&nbsp;* The path corresponds to the succession of nodes</div><div>&nbsp;* in the order they are retured by the Iterator</div><div>&nbsp;*</div><div>&nbsp;* @author Emmanuel Bernard</div><div>&nbsp;*/</div><div>public interface Path extends Iterable&lt;Node&gt; {</div><div>}</div><div><br></div><div><br></div><div>A node represent a path element.</div><div><br></div><div><div>/**</div><div>&nbsp;* Represents an element of a navigation path</div><div>&nbsp;*</div><div>&nbsp;* @author Emmanuel Bernard</div><div>&nbsp;*/</div><div>public interface Node {</div><div><span class="Apple-tab-span" style="white-space:pre">        </span>/**</div><div><span class="Apple-tab-span" style="white-space:pre">        </span> * Property name the node represents</div><div><span class="Apple-tab-span" style="white-space:pre">        </span> * or null if the leaf node and representing an entity</div><div><span class="Apple-tab-span" style="white-space:pre">        </span> * (in particular the node representing the root object</div><div><span class="Apple-tab-span" style="white-space:pre">        </span> * has its name null)</div><div><span class="Apple-tab-span" style="white-space:pre">        </span> */</div><div><span class="Apple-tab-span" style="white-space:pre">        </span>String getName();</div><div><br></div><div><span class="Apple-tab-span" style="white-space:pre">        </span>/**</div><div><span class="Apple-tab-span" style="white-space:pre">        </span> * True if the node represents an object contained in an Iterable</div><div><span class="Apple-tab-span" style="white-space:pre">        </span> * or in a Map.</div><div><span class="Apple-tab-span" style="white-space:pre">        </span> */</div><div><span class="Apple-tab-span" style="white-space:pre">        </span>boolean isInIterable();</div><div><br></div><div><span class="Apple-tab-span" style="white-space:pre">        </span>/**</div><div><span class="Apple-tab-span" style="white-space:pre">        </span> * The index the node is placed in if contained</div><div><span class="Apple-tab-span" style="white-space:pre">        </span> * in an array or List. Null otherwise.</div><div><span class="Apple-tab-span" style="white-space:pre">        </span> */</div><div><span class="Apple-tab-span" style="white-space:pre">        </span>Integer getIndex();</div><div><br></div><div><span class="Apple-tab-span" style="white-space:pre">        </span>/**</div><div><span class="Apple-tab-span" style="white-space:pre">        </span> * The key the node is placed in if contained</div><div><span class="Apple-tab-span" style="white-space:pre">        </span> * in a Map. Null otherwise.</div><div><span class="Apple-tab-span" style="white-space:pre">        </span> */</div><div><span class="Apple-tab-span" style="white-space:pre">        </span>Object getKey();</div><div>}</div><div><br></div><div>A few interesting points:</div><div>&nbsp;- the index / key is hosted by the node after the collection node</div><div><br></div><div>Here are a few examples and their Node equivalent</div><div><br></div><div>""</div><div>0: Node(name:null, isInIterable:false, index:null, key:null)</div></div><div><br></div><div><div><div>"email"</div><div>0: Node(name:email, isInIterable:false, index:null, key:null)</div><div><br></div><div><div><div>"addresses"</div><div>0: Node(name:addresses, isInIterable:false, index:null, key:null)</div><div><br></div><div><div><div>"addresses["home"]" represent the bean level of an Address object</div><div>0: Node(name:addresses, isInIterable:false, index:null, key:null)</div><div>1: Node(name:null, isInIterable:true, index:null, key:home)</div><div><br></div><div><div>"addresses["home"].city"</div><div>0: Node(name:addresses, isInIterable:false, index:null, key:null)</div><div>1: Node(name:city, isInIterable:true, index:null, key:home)</div><div><br></div></div></div></div><div><div>"billingAddresses[3].country.name"</div><div>0: Node(name:billingAddresses, isInIterable:false, index:null, key:null)</div><div>1: Node(name:country, isInIterable:true, index:3, key:null)</div><div>2: Node(name:name, isInIterable:false, index:null, key:null)</div><div><br></div><div><br></div><div>ConstraintViolation renders a Path</div><div><br></div><div>public interface ConstraintViolation&lt;T&gt; {</div><div>&nbsp;&nbsp; &nbsp;Path getPropertyPath();</div><div>}</div><div><br></div><div>TraversableResolver accepts a path</div><div><br></div><div>public interface TraversableResolver {</div><div><div><span class="Apple-tab-span" style="white-space:pre">        </span>boolean isReachable(Object traversableObject,</div><div><span class="Apple-tab-span" style="white-space:pre">                                                </span> &nbsp;String traversableProperty,</div><div><span class="Apple-tab-span" style="white-space:pre">                                                </span> &nbsp;Class&lt;?&gt; rootBeanType,</div><div><span class="Apple-tab-span" style="white-space:pre">                                                </span> &nbsp;Path pathToTraversableObject,</div><div><span class="Apple-tab-span" style="white-space:pre">                                                </span> &nbsp;ElementType elementType);</div><div>&nbsp;&nbsp; &nbsp;...</div><div>}</div><div><br></div><div>PS: should&nbsp;String traversableProperty be Node&nbsp;traversableProperty ?</div></div></div></div></div><div><br></div></div></div><div><br><div><div>On &nbsp;May 27, 2009, at 12:19, Emmanuel Bernard wrote:</div><br class="Apple-interchange-newline"><blockquote type="cite"><div style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space; ">In several areas we do describe path:<div>&nbsp;- ConstraintViolation</div><div>&nbsp;- ConstraintValidatorContext (with addError(String, String) which allows to concatenate substrings</div><div><br></div><div>So far we use the notion of string to represent it</div><div>&nbsp;- address.name</div><div>&nbsp;- cards[3].color</div><div>&nbsp;- addresses["home"].city</div><div><br></div><div>I have added the idea of using [] for simple Iterable objects (ie non indexed, like a Set)</div><div>&nbsp;- accounts[].balance</div><div><br></div><div>Anybody objects to that?</div><div><br></div><div>Second point</div><div>Do we want to replace this String approach with a path object mode?</div><div><br></div><div><a href="http://opensource.atlassian.com/projects/hibernate/browse/BVAL-143">http://opensource.atlassian.com/projects/hibernate/browse/BVAL-143</a></div><div><font class="Apple-style-span" face="Arial">______</font></div><div><span class="Apple-style-span" style="font-family: Arial; ">path are today strings with dot separating properties. But it break when Set or Iterable are used.&nbsp;<br>We could replace that with&nbsp;<br>--- First strawman, must evolve --&nbsp;<br>class PathElement {&nbsp;<br>&nbsp;&nbsp;String getName();&nbsp;<br>&nbsp;&nbsp;PathElement getParentPath();&nbsp;<br>&nbsp;&nbsp;boolean isIterable();&nbsp;<br>&nbsp;&nbsp;boolean isIndexed();&nbsp;<br>&nbsp;&nbsp;Object getIndex();&nbsp;<br>&nbsp;&nbsp;//TODO int getIndex()?&nbsp;<br><br>&nbsp;&nbsp;// not happy about that as it is only useful for Constraintciolation&nbsp;<br>&nbsp;&nbsp;PathElement getChild();&nbsp;<br>}&nbsp;<br><br>PathElement would be used for Constraintvuilation, maybe CVContext etc&nbsp;<br><br>can this be refactored using inheritance + generics to have an IndexedPathElement only when it matters (probably no unfortunately)&nbsp;</span></div><div><font class="Apple-style-span" face="Arial">______</font></div><div><font class="Apple-style-span" face="Arial"><br></font></div><div><br></div><div>Pros:</div><div>&nbsp;- less string manipulation by the user and the TraversableResolver implementation</div><div>&nbsp;- the map index no longer rely on "[" + toString() + "]" and is likely more easily handled</div><div><br></div><div>Cons:</div><div>&nbsp;-&nbsp;ConstraintValidatorContext becomes more complex as it needs to expose some kind of path element builder.</div><div>&nbsp;- we would like need to standardize some kind of String serialization anyway</div><div>&nbsp;- I don't see Pros as huge advantages</div><div><br></div><div>WDYT?</div></div></blockquote></div><br></div></div></div></blockquote></div><br></body></html>