<html><body style="word-wrap: break-word; -webkit-nbsp-mode: space; -webkit-line-break: after-white-space; ">The constraintValidatorContext fluent API for building errors. Please review.<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 <<a href="mailto:emmanuel.bernard@jboss.com">emmanuel.bernard@jboss.com</a>></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"> </span></b></font><font face="Helvetica" size="3" style="font: 12.0px Helvetica"> June 18, 2009 16:55:06<span class="Apple-converted-space"> </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: </b></font><font face="Helvetica" size="3" style="font: 12.0px Helvetica"><a href="mailto:jsr-303-eg@jcp.org">jsr-303-eg@jcp.org</a></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: [jsr-303-eg] 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 for ConstraintValidatorContext.<div>I've designed a fluent API to create error reports and add their message and potentially their sub nodes and the appropriate contextual information.</div><div><br></div><div>Here is a usage example</div><div><br></div><div><div><span class="Apple-tab-span" style="white-space: pre; ">        </span>public boolean isValid(String value, ConstraintValidatorContext context) {</div><div><span class="Apple-tab-span" style="white-space:pre">                </span>//default path</div><div><span class="Apple-tab-span" style="white-space:pre">                </span>context.buildErrorWithMessage( "this detail is wrong" ).addError();</div><div><br></div><div><span class="Apple-tab-span" style="white-space: pre; ">                </span>//default path + "street"</div><div><span class="Apple-tab-span" style="white-space:pre">                </span>context.buildErrorWithMessage( "this detail is wrong" )</div><div><span class="Apple-tab-span" style="white-space:pre">                                        </span>.inSubNode( "street" )</div><div><span class="Apple-tab-span" style="white-space:pre">                                        </span>.addError();</div><div><br></div><div><span class="Apple-tab-span" style="white-space:pre">                </span>//default path + "addresses["home"].country.name</div><div><span class="Apple-tab-span" style="white-space:pre">                </span>context.buildErrorWithMessage( "this detail is wrong" )</div><div><span class="Apple-tab-span" style="white-space:pre">                                        </span>.inSubNode( "addresses" )</div><div><span class="Apple-tab-span" style="white-space:pre">                                        </span>.inSubNode( "country" )</div><div><span class="Apple-tab-span" style="white-space:pre">                                                </span>.inIterable().atKey( "home" )</div><div><span class="Apple-tab-span" style="white-space:pre">                                        </span>.inSubNode( "name" )</div><div><span class="Apple-tab-span" style="white-space:pre">                                        </span>.addError();</div><div><span class="Apple-tab-span" style="white-space:pre">                </span>return false;</div><div><span class="Apple-tab-span" style="white-space:pre">        </span>}</div></div><div><br></div><div>I've used a nested interface model to keep things clean. Please review and comment.</div><div><br></div><div><div>/**</div><div> * Provide contextual data and operation when applying a given constraint validator</div><div> *</div><div> * @author Emmanuel Bernard</div><div> */</div><div>public interface ConstraintValidatorContext {</div><div><span class="Apple-tab-span" style="white-space:pre">        </span>/**</div><div><span class="Apple-tab-span" style="white-space:pre">        </span> * Disable the default error message and default ConstraintViolation object generation.</div><div><span class="Apple-tab-span" style="white-space:pre">        </span> * Useful to set a different error message or generate a ConstraintViolation based on</div><div><span class="Apple-tab-span" style="white-space:pre">        </span> * a different property</div><div><span class="Apple-tab-span" style="white-space:pre">        </span> */</div><div><span class="Apple-tab-span" style="white-space:pre">        </span>void disableDefaultError();</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> * @return the current uninterpolated default message</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 getDefaultErrorMessage();</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> * Return an error builder building an error allowing to optionally associate</div><div><span class="Apple-tab-span" style="white-space:pre">        </span> * the error to a sub path.</div><div><span class="Apple-tab-span" style="white-space:pre">        </span> * The error message will be interpolated.</div><div><span class="Apple-tab-span" style="white-space:pre">        </span> * <p/></div><div><span class="Apple-tab-span" style="white-space:pre">        </span> * To create the error, one must call either one of</div><div><span class="Apple-tab-span" style="white-space:pre">        </span> * the #addError method available in one of the</div><div><span class="Apple-tab-span" style="white-space:pre">        </span> * interfaces of the fluent API.</div><div><span class="Apple-tab-span" style="white-space:pre">        </span> * If another method is called after #addError() on</div><div><span class="Apple-tab-span" style="white-space:pre">        </span> * ErrorBuilder or any of its associated nested interfaces</div><div><span class="Apple-tab-span" style="white-space:pre">        </span> * an IllegalStateException is raised.</div><div><span class="Apple-tab-span" style="white-space:pre">        </span> * <p/></div><div><span class="Apple-tab-span" style="white-space:pre">        </span> * If <code>isValid<code> returns <code>false</code>, a <code>ConstraintViolation</code> object will be built</div><div><span class="Apple-tab-span" style="white-space:pre">        </span> * per error including the default one unless {@link #disableDefaultError()} has been called.</div><div><span class="Apple-tab-span" style="white-space:pre">        </span> * <p/></div><div><span class="Apple-tab-span" style="white-space:pre">        </span> * <code>ConstraintViolation</code> objects generated from such a call</div><div><span class="Apple-tab-span" style="white-space:pre">        </span> * contain the same contextual information (root bean, path and so on) unless</div><div><span class="Apple-tab-span" style="white-space:pre">        </span> * the path has been overriden.</div><div><span class="Apple-tab-span" style="white-space:pre">        </span> * <p/></div><div><span class="Apple-tab-span" style="white-space:pre">        </span> * To create a different error, a new error builder has to be retrieved from</div><div><span class="Apple-tab-span" style="white-space:pre">        </span> * ConstraintValidatorContext</div><div><span class="Apple-tab-span" style="white-space:pre">        </span> *</div><div><span class="Apple-tab-span" style="white-space:pre">        </span> * Here are a few usage examples:</div><div><span class="Apple-tab-span" style="white-space:pre">        </span> * <pre>//create new error with the default path the constraint</div><div><span class="Apple-tab-span" style="white-space:pre">        </span> * //is located on</div><div><span class="Apple-tab-span" style="white-space:pre">        </span> * context.buildErrorWithMessage( "way too long" )</div><div><span class="Apple-tab-span" style="white-space:pre">        </span> * .addError();</div><div><span class="Apple-tab-span" style="white-space:pre">        </span> *</div><div><span class="Apple-tab-span" style="white-space:pre">        </span> * //create new error in the "street" subnode of the default</div><div><span class="Apple-tab-span" style="white-space:pre">        </span> * //path the constraint is located on</div><div><span class="Apple-tab-span" style="white-space:pre">        </span> * context.buildErrorWithMessage( "way too long" )</div><div><span class="Apple-tab-span" style="white-space:pre">        </span> * .inSubNode( "street" )</div><div><span class="Apple-tab-span" style="white-space:pre">        </span> * .addError();</div><div><span class="Apple-tab-span" style="white-space:pre">        </span> *</div><div><span class="Apple-tab-span" style="white-space:pre">        </span> * //create new error in the "addresses["home"].city.name</div><div><span class="Apple-tab-span" style="white-space:pre">        </span> * //subnode of the default path the constraint is located on</div><div><span class="Apple-tab-span" style="white-space:pre">        </span> * context.buildErrorWithMessage( "this detail is wrong" )</div><div><span class="Apple-tab-span" style="white-space:pre">        </span> * .inSubNode( "addresses" )</div><div><span class="Apple-tab-span" style="white-space:pre">        </span> * .inSubNode( "country" )</div><div><span class="Apple-tab-span" style="white-space:pre">        </span> * .inIterable().atKey( "home" )</div><div><span class="Apple-tab-span" style="white-space:pre">        </span> * .inSubNode( "name" )</div><div><span class="Apple-tab-span" style="white-space:pre">        </span> * .addError();</div><div><span class="Apple-tab-span" style="white-space:pre">        </span> * </pre></div><div><span class="Apple-tab-span" style="white-space:pre">        </span> *</div><div><span class="Apple-tab-span" style="white-space:pre">        </span> * @param message new uninterpolated error message.</div><div><span class="Apple-tab-span" style="white-space:pre">        </span> */</div><div><span class="Apple-tab-span" style="white-space:pre">        </span>ErrorBuilder buildErrorWithMessage(String message);</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> * Error builder allowing to optionally associate</div><div><span class="Apple-tab-span" style="white-space:pre">        </span> * the error to a sub path.</div><div><span class="Apple-tab-span" style="white-space:pre">        </span> *</div><div><span class="Apple-tab-span" style="white-space:pre">        </span> * To create the error, one must call either one of</div><div><span class="Apple-tab-span" style="white-space:pre">        </span> * the #addError method available in one of the</div><div><span class="Apple-tab-span" style="white-space:pre">        </span> * interfaces of the fluent API.</div><div><span class="Apple-tab-span" style="white-space:pre">        </span> * If another method is called after #addError() on</div><div><span class="Apple-tab-span" style="white-space:pre">        </span> * ErrorBuilder or any of its associated objects</div><div><span class="Apple-tab-span" style="white-space:pre">        </span> * an IllegalStateException is raised.</div><div><span class="Apple-tab-span" style="white-space:pre">        </span> * </div><div><span class="Apple-tab-span" style="white-space:pre">        </span> */</div><div><span class="Apple-tab-span" style="white-space:pre">        </span>interface ErrorBuilder {</div><div><span class="Apple-tab-span" style="white-space:pre">                </span>/**</div><div><span class="Apple-tab-span" style="white-space:pre">                </span> * Add a subNode to the path the error will be associated to</div><div><span class="Apple-tab-span" style="white-space:pre">                </span> *</div><div><span class="Apple-tab-span" style="white-space:pre">                </span> * @param name property</div><div><span class="Apple-tab-span" style="white-space:pre">                </span> * @return a builder representing the first level 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>NodeBuilder inSubNode(String name);</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> * Add the new error report to be generated if the</div><div><span class="Apple-tab-span" style="white-space:pre">                </span> * constraint validator mark the value as invalid.</div><div><span class="Apple-tab-span" style="white-space:pre">                </span> * Methods of this ErrorBuilder instance and its nested</div><div><span class="Apple-tab-span" style="white-space:pre">                </span> * objects returns IllegalStateException from now on.</div><div><span class="Apple-tab-span" style="white-space:pre">                </span> *</div><div><span class="Apple-tab-span" style="white-space:pre">                </span> * @return ConstraintValidatorContext instance the ErrorBuilder comes from </div><div><span class="Apple-tab-span" style="white-space:pre">                </span> */</div><div><span class="Apple-tab-span" style="white-space:pre">                </span>ConstraintValidatorContext addError();</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> * Represent asubnode whose context is known</div><div><span class="Apple-tab-span" style="white-space:pre">                </span> * (ie index, key and isInIterable)</div><div><span class="Apple-tab-span" style="white-space:pre">                </span> */</div><div><span class="Apple-tab-span" style="white-space:pre">                </span>interface NodeBuilder {</div><div><span class="Apple-tab-span" style="white-space:pre">                        </span>/**</div><div><span class="Apple-tab-span" style="white-space:pre">                        </span> * Add a subNode to the path the error will be associated to</div><div><span class="Apple-tab-span" style="white-space:pre">                        </span> *</div><div><span class="Apple-tab-span" style="white-space:pre">                        </span> * @param name property</div><div><span class="Apple-tab-span" style="white-space:pre">                        </span> * @return a builder representing this 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>InIterableNodeBuilder inSubNode(String name);</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> * Add the new error report to be generated if the</div><div><span class="Apple-tab-span" style="white-space:pre">                        </span> * constraint validator mark the value as invalid.</div><div><span class="Apple-tab-span" style="white-space:pre">                        </span> * Methods of the ErrorBuilder instance this object comes</div><div><span class="Apple-tab-span" style="white-space:pre">                        </span> * from and the error builder nested</div><div><span class="Apple-tab-span" style="white-space:pre">                        </span> * objects returns IllegalStateException from now on.</div><div><span class="Apple-tab-span" style="white-space:pre">                        </span> *</div><div><span class="Apple-tab-span" style="white-space:pre">                        </span> * @return ConstraintValidatorContext instance the ErrorBuilder comes from</div><div><span class="Apple-tab-span" style="white-space:pre">                        </span> */</div><div><span class="Apple-tab-span" style="white-space:pre">                        </span>ConstraintValidatorContext addError();</div><div><span class="Apple-tab-span" style="white-space:pre">                </span>}</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> * Represent a subnode whose context is</div><div><span class="Apple-tab-span" style="white-space:pre">                </span> * configurable (ie index, key and isInIterable)</div><div><span class="Apple-tab-span" style="white-space:pre">                </span> */</div><div><span class="Apple-tab-span" style="white-space:pre">                </span>interface InIterableNodeBuilder {</div><div><span class="Apple-tab-span" style="white-space:pre">                        </span>/**</div><div><span class="Apple-tab-span" style="white-space:pre">                        </span> * Mark the node as being in an Iterable or a Map</div><div><span class="Apple-tab-span" style="white-space:pre">                        </span> * @return a builder representing iterable details</div><div><span class="Apple-tab-span" style="white-space:pre">                        </span> */</div><div><span class="Apple-tab-span" style="white-space:pre">                        </span>InIterablePropertiesBuilder inIterable();</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> * Add a subNode to the path the error will be associated to</div><div><span class="Apple-tab-span" style="white-space:pre">                        </span> *</div><div><span class="Apple-tab-span" style="white-space:pre">                        </span> * @param name property</div><div><span class="Apple-tab-span" style="white-space:pre">                        </span> * @return a builder representing this 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>InIterableNodeBuilder inSubNode(String name);</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> * Add the new error report to be generated if the</div><div><span class="Apple-tab-span" style="white-space:pre">                        </span> * constraint validator mark the value as invalid.</div><div><span class="Apple-tab-span" style="white-space:pre">                        </span> * Methods of the ErrorBuilder instance this object comes</div><div><span class="Apple-tab-span" style="white-space:pre">                        </span> * from and the error builder nested</div><div><span class="Apple-tab-span" style="white-space:pre">                        </span> * objects returns IllegalStateException from now on.</div><div><span class="Apple-tab-span" style="white-space:pre">                        </span> *</div><div><span class="Apple-tab-span" style="white-space:pre">                        </span> * @return ConstraintValidatorContext instance the ErrorBuilder comes from</div><div><span class="Apple-tab-span" style="white-space:pre">                        </span> */</div><div><span class="Apple-tab-span" style="white-space:pre">                        </span>ConstraintValidatorContext addError();</div><div><span class="Apple-tab-span" style="white-space:pre">                </span>}</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> * Represent choices for a node which is</div><div><span class="Apple-tab-span" style="white-space:pre">                </span> * in an Iterator or Map.</div><div><span class="Apple-tab-span" style="white-space:pre">                </span> * If the iterator is an indexed collection or a map,</div><div><span class="Apple-tab-span" style="white-space:pre">                </span> * the index or the key should be set.</div><div><span class="Apple-tab-span" style="white-space:pre">                </span> */</div><div><span class="Apple-tab-span" style="white-space:pre">                </span>interface InIterablePropertiesBuilder {</div><div><span class="Apple-tab-span" style="white-space:pre">                        </span>/**</div><div><span class="Apple-tab-span" style="white-space:pre">                        </span> * Define the key the object is into the 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> * @param key map key</div><div><span class="Apple-tab-span" style="white-space:pre">                        </span> * @return a builder representing the current 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>NodeBuilder atKey(Object key);</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> * Define the index the object is into the List or array</div><div><span class="Apple-tab-span" style="white-space:pre">                        </span> *</div><div><span class="Apple-tab-span" style="white-space:pre">                        </span> * @param index index</div><div><span class="Apple-tab-span" style="white-space:pre">                        </span> * @return a builder representing the current 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>NodeBuilder atIndex(Integer index);</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> * Add a subNode to the path the error will be associated to</div><div><span class="Apple-tab-span" style="white-space:pre">                        </span> *</div><div><span class="Apple-tab-span" style="white-space:pre">                        </span> * @param name property</div><div><span class="Apple-tab-span" style="white-space:pre">                        </span> * @return a builder representing this 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>InIterableNodeBuilder inSubNode(String name);</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> * Add the new error report to be generated if the</div><div><span class="Apple-tab-span" style="white-space:pre">                        </span> * constraint validator mark the value as invalid.</div><div><span class="Apple-tab-span" style="white-space:pre">                        </span> * Methods of the ErrorBuilder instance this object comes</div><div><span class="Apple-tab-span" style="white-space:pre">                        </span> * from and the error builder nested</div><div><span class="Apple-tab-span" style="white-space:pre">                        </span> * objects returns IllegalStateException from now on.</div><div><span class="Apple-tab-span" style="white-space:pre">                        </span> *</div><div><span class="Apple-tab-span" style="white-space:pre">                        </span> * @return ConstraintValidatorContext instance the ErrorBuilder comes from</div><div><span class="Apple-tab-span" style="white-space:pre">                        </span> */</div><div><span class="Apple-tab-span" style="white-space:pre">                        </span>ConstraintValidatorContext addError();</div><div><span class="Apple-tab-span" style="white-space:pre">                </span>}</div><div><span class="Apple-tab-span" style="white-space:pre">        </span>}</div><div>}</div></div><div><br></div><div><br><div><div>On Jun 17, 2009, at 14:41, 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; ">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 Iterable of Nodes.</div><div><br></div><div><div>/**</div><div> * Represent a navigation path from an object to another.</div><div> * Each path element is represented by a Node.</div><div> *</div><div> * The path corresponds to the succession of nodes</div><div> * in the order they are retured by the Iterator</div><div> *</div><div> * @author Emmanuel Bernard</div><div> */</div><div>public interface Path extends Iterable<Node> {</div><div>}</div><div><br></div><div><br></div><div>A node represent a path element.</div><div><br></div><div><div>/**</div><div> * Represents an element of a navigation path</div><div> *</div><div> * @author Emmanuel Bernard</div><div> */</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> - 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<T> {</div><div> 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> String traversableProperty,</div><div><span class="Apple-tab-span" style="white-space:pre">                                                </span> Class<?> rootBeanType,</div><div><span class="Apple-tab-span" style="white-space:pre">                                                </span> Path pathToTraversableObject,</div><div><span class="Apple-tab-span" style="white-space:pre">                                                </span> ElementType elementType);</div><div> ...</div><div>}</div><div><br></div><div>PS: should String traversableProperty be Node traversableProperty ?</div></div></div></div></div><div><br></div></div></div><div><br><div><div>On 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> - ConstraintViolation</div><div> - 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> - address.name</div><div> - cards[3].color</div><div> - 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> - 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. <br>We could replace that with <br>--- First strawman, must evolve -- <br>class PathElement { <br> String getName(); <br> PathElement getParentPath(); <br> boolean isIterable(); <br> boolean isIndexed(); <br> Object getIndex(); <br> //TODO int getIndex()? <br><br> // not happy about that as it is only useful for Constraintciolation <br> PathElement getChild(); <br>} <br><br>PathElement would be used for Constraintvuilation, maybe CVContext etc <br><br>can this be refactored using inheritance + generics to have an IndexedPathElement only when it matters (probably no unfortunately) </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> - less string manipulation by the user and the TraversableResolver implementation</div><div> - the map index no longer rely on "[" + toString() + "]" and is likely more easily handled</div><div><br></div><div>Cons:</div><div> - ConstraintValidatorContext becomes more complex as it needs to expose some kind of path element builder.</div><div> - we would like need to standardize some kind of String serialization anyway</div><div> - I don't see Pros as huge advantages</div><div><br></div><div>WDYT?</div></div></blockquote></div><br></div></div></div>_______________________________________________<br>jsr-303-eg mailing list <a href="mailto:jsr-303-eg@jcp.org">jsr-303-eg@jcp.org</a></blockquote></div><br></div></div></blockquote></div><br></body></html>