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