Author: epbernard
Date: 2009-06-22 09:54:37 -0400 (Mon, 22 Jun 2009)
New Revision: 16854
Added:
beanvalidation/trunk/validation-api/src/main/java/javax/validation/Path.java
Modified:
beanvalidation/trunk/validation-api/src/main/java/javax/validation/ConstraintValidatorContext.java
beanvalidation/trunk/validation-api/src/main/java/javax/validation/ConstraintViolation.java
beanvalidation/trunk/validation-api/src/main/java/javax/validation/TraversableResolver.java
Log:
BVAL-143 Describe path with an object model
Modified:
beanvalidation/trunk/validation-api/src/main/java/javax/validation/ConstraintValidatorContext.java
===================================================================
---
beanvalidation/trunk/validation-api/src/main/java/javax/validation/ConstraintValidatorContext.java 2009-06-22
13:53:50 UTC (rev 16853)
+++
beanvalidation/trunk/validation-api/src/main/java/javax/validation/ConstraintValidatorContext.java 2009-06-22
13:54:37 UTC (rev 16854)
@@ -27,52 +27,190 @@
* Disable the default error message and default ConstraintViolation object generation.
* Useful to set a different error message or generate a ConstraintViolation based on
* a different property
- *
- * @see #addError(String)
- * @see #addError(String, String)
*/
void disableDefaultError();
/**
* @return the current uninterpolated default message
*/
- String getDefaultErrorMessage();
+ String getDefaultErrorMessageTemplate();
/**
- * Add a new error message. This error message will be interpolated.
+ * Return an error builder building an error allowing to optionally associate
+ * the error to a sub path.
+ * The error message will be interpolated.
* <p/>
+ * To create the error, one must call either one of
+ * the #addError method available in one of the
+ * interfaces of the fluent API.
+ * If another method is called after #addError() on
+ * ErrorBuilder or any of its associated nested interfaces
+ * an IllegalStateException is raised.
+ * <p/>
* If <code>isValid<code> returns <code>false</code>, a
<code>ConstraintViolation</code> object will be built
- * per error message including the default one unless {@link #disableDefaultError()} has
been called.
+ * per error including the default one unless {@link #disableDefaultError()} has been
called.
* <p/>
- * Aside from the error message, <code>ConstraintViolation</code> objects
generated from such a call
- * contain the same contextual information (root bean, path and so on)
+ * <code>ConstraintViolation</code> objects generated from such a call
+ * contain the same contextual information (root bean, path and so on) unless
+ * the path has been overriden.
* <p/>
- * This method can be called multiple times. One
<code>ConstraintViolation</code> instance per
- * call is created.
+ * To create a different error, a new error builder has to be retrieved from
+ * ConstraintValidatorContext
*
- * @param message new uninterpolated error message.
+ * Here are a few usage examples:
+ * <pre>//create new error with the default path the constraint
+ * //is located on
+ * context.buildErrorWithMessageTemplate( "way too long" )
+ * .addError();
+ *
+ * //create new error in the "street" subnode of the default
+ * //path the constraint is located on
+ * context.buildErrorWithMessageTemplate( "way too long" )
+ * .inSubNode( "street" )
+ * .addError();
+ *
+ * //create new error in the "addresses["home"].city.name
+ * //subnode of the default path the constraint is located on
+ * context.buildErrorWithMessageTemplate( "this detail is wrong" )
+ * .inSubNode( "addresses" )
+ * .inSubNode( "country" )
+ * .inIterable().atKey( "home" )
+ * .inSubNode( "name" )
+ * .addError();
+ * </pre>
+ *
+ * @param messageTemplate new uninterpolated error message.
*/
- void addError(String message);
+ ErrorBuilder buildErrorWithMessageTemplate(String messageTemplate);
/**
- * Add a new error message to a given sub property <code>property</code>.
The subproperty
- * is relative to the path to the bean or property hosting the constraint.
+ * Error builder allowing to optionally associate
+ * the error to a sub path.
*
- * This error message will be interpolated.
- * <p/>
- * If <code>isValid</code> returns <code>false</code>, a
<code>ConstraintViolation</code> object will be built
- * per error message including the default one unless {@link #disableDefaultError()}
- * has been called.
- * <p/>
- * Aside from the error message and the property path,
<code>ConstraintViolation</code> objects
- * generated from such a call contain the same contextual information
- * (root bean, leaf bean etc)
- * <p/>
- * This method can be called multiple times. One
<code>ConstraintViolation</code> instance per
- * call is created.
- *
- * @param message new uninterpolated error message.
- * @param property property name the </code>ConstraintViolation</code> is
targeting.
+ * To create the error, one must call either one of
+ * the #addError method available in one of the
+ * interfaces of the fluent API.
+ * If another method is called after #addError() on
+ * ErrorBuilder or any of its associated objects
+ * an IllegalStateException is raised.
+ *
*/
- void addError(String message, String property);
+ interface ErrorBuilder {
+ /**
+ * Add a subNode to the path the error will be associated to
+ *
+ * @param name property
+ * @return a builder representing the first level node
+ */
+ NodeBuilder inSubNode(String name);
+
+ /**
+ * Add the new error report to be generated if the
+ * constraint validator mark the value as invalid.
+ * Methods of this ErrorBuilder instance and its nested
+ * objects returns IllegalStateException from now on.
+ *
+ * @return ConstraintValidatorContext instance the ErrorBuilder comes from
+ */
+ ConstraintValidatorContext addError();
+
+ /**
+ * Represent asubnode whose context is known
+ * (ie index, key and isInIterable)
+ */
+ interface NodeBuilder {
+ /**
+ * Add a subNode to the path the error will be associated to
+ *
+ * @param name property
+ * @return a builder representing this node
+ */
+ InIterableNodeBuilder inSubNode(String name);
+
+ /**
+ * Add the new error report to be generated if the
+ * constraint validator mark the value as invalid.
+ * Methods of the ErrorBuilder instance this object comes
+ * from and the error builder nested
+ * objects returns IllegalStateException from now on.
+ *
+ * @return ConstraintValidatorContext instance the ErrorBuilder comes from
+ */
+ ConstraintValidatorContext addError();
+ }
+
+ /**
+ * Represent a subnode whose context is
+ * configurable (ie index, key and isInIterable)
+ */
+ interface InIterableNodeBuilder {
+ /**
+ * Mark the node as being in an Iterable or a Map
+ * @return a builder representing iterable details
+ */
+ InIterablePropertiesBuilder inIterable();
+
+ /**
+ * Add a subNode to the path the error will be associated to
+ *
+ * @param name property
+ * @return a builder representing this node
+ */
+ InIterableNodeBuilder inSubNode(String name);
+
+ /**
+ * Add the new error report to be generated if the
+ * constraint validator mark the value as invalid.
+ * Methods of the ErrorBuilder instance this object comes
+ * from and the error builder nested
+ * objects returns IllegalStateException from now on.
+ *
+ * @return ConstraintValidatorContext instance the ErrorBuilder comes from
+ */
+ ConstraintValidatorContext addError();
+ }
+
+ /**
+ * Represent choices for a node which is
+ * in an Iterator or Map.
+ * If the iterator is an indexed collection or a map,
+ * the index or the key should be set.
+ */
+ interface InIterablePropertiesBuilder {
+ /**
+ * Define the key the object is into the Map
+ *
+ * @param key map key
+ * @return a builder representing the current node
+ */
+ NodeBuilder atKey(Object key);
+
+ /**
+ * Define the index the object is into the List or array
+ *
+ * @param index index
+ * @return a builder representing the current node
+ */
+ NodeBuilder atIndex(Integer index);
+
+ /**
+ * Add a subNode to the path the error will be associated to
+ *
+ * @param name property
+ * @return a builder representing this node
+ */
+ InIterableNodeBuilder inSubNode(String name);
+
+ /**
+ * Add the new error report to be generated if the
+ * constraint validator mark the value as invalid.
+ * Methods of the ErrorBuilder instance this object comes
+ * from and the error builder nested
+ * objects returns IllegalStateException from now on.
+ *
+ * @return ConstraintValidatorContext instance the ErrorBuilder comes from
+ */
+ ConstraintValidatorContext addError();
+ }
+ }
}
Modified:
beanvalidation/trunk/validation-api/src/main/java/javax/validation/ConstraintViolation.java
===================================================================
---
beanvalidation/trunk/validation-api/src/main/java/javax/validation/ConstraintViolation.java 2009-06-22
13:53:50 UTC (rev 16853)
+++
beanvalidation/trunk/validation-api/src/main/java/javax/validation/ConstraintViolation.java 2009-06-22
13:54:37 UTC (rev 16854)
@@ -18,6 +18,7 @@
package javax.validation;
import javax.validation.metadata.ConstraintDescriptor;
+import javax.validation.Path;
/**
* Describe a constraint violation. This object describe the error context as
@@ -59,10 +60,9 @@
Object getLeafBean();
/**
- * @return the property path to the value from <code>rootBean</code>
- * <code>null</code> if the value is the
<code>rootBean<code> itself.
+ * @return the property path to the value from <code>rootBean</code>.
*/
- String getPropertyPath();
+ Path getPropertyPath();
/**
* @return the value failing to pass the constraint.
Added: beanvalidation/trunk/validation-api/src/main/java/javax/validation/Path.java
===================================================================
--- beanvalidation/trunk/validation-api/src/main/java/javax/validation/Path.java
(rev 0)
+++
beanvalidation/trunk/validation-api/src/main/java/javax/validation/Path.java 2009-06-22
13:54:37 UTC (rev 16854)
@@ -0,0 +1,44 @@
+package javax.validation;
+
+/**
+ * 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<Path.Node> {
+
+ /**
+ * Represents an element of a navigation path
+ */
+ 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();
+ }
+}
Modified:
beanvalidation/trunk/validation-api/src/main/java/javax/validation/TraversableResolver.java
===================================================================
---
beanvalidation/trunk/validation-api/src/main/java/javax/validation/TraversableResolver.java 2009-06-22
13:53:50 UTC (rev 16853)
+++
beanvalidation/trunk/validation-api/src/main/java/javax/validation/TraversableResolver.java 2009-06-22
13:54:37 UTC (rev 16854)
@@ -18,6 +18,7 @@
package javax.validation;
import java.lang.annotation.ElementType;
+import javax.validation.Path;
/**
* Contract determining if a property can be accessed by the Bean Validation provider
@@ -32,11 +33,10 @@
* Determine if Bean Validation is allowed to reach the property state
*
* @param traversableObject object hosting <code>traversableProperty</code>,
null if validateValue is called
- * @param traversableProperty name of the traversable property.
+ * @param traversableProperty the traversable property.
* @param rootBeanType type of the root object passed to the Validator.
* @param pathToTraversableObject path from the root object to
- * <code>traversableObject</code> ("" if the
<code>traversableObject</code>
- * is the root object)
+ * <code>traversableObject</code>
* (using the path specification defined by Bean Validator).
* @param elementType either <code>FIELD</code> or
<code>METHOD</code>.
*
@@ -44,9 +44,9 @@
* <code>false</code> otherwise.
*/
boolean isReachable(Object traversableObject,
- String traversableProperty,
+ Path.Node traversableProperty,
Class<?> rootBeanType,
- String pathToTraversableObject,
+ Path pathToTraversableObject,
ElementType elementType);
/**
@@ -57,11 +57,10 @@
* arguments and if the property is marked as <code>@Valid</code>
*
* @param traversableObject object hosting <code>traversableProperty</code>,
null if validateValue is called
- * @param traversableProperty name of the traversable property.
+ * @param traversableProperty the traversable property.
* @param rootBeanType type of the root object passed to the Validator.
* @param pathToTraversableObject path from the root object to
- * <code>traversableObject</code> ("" if the
<code>traversableObject</code>
- * is the root object)
+ * <code>traversableObject</code>
* (using the path specification defined by Bean Validator).
* @param elementType either <code>FIELD</code> or
<code>METHOD</code>.
*
@@ -69,8 +68,8 @@
* <code>false</code> otherwise.
*/
boolean isCascadable(Object traversableObject,
- String traversableProperty,
+ Path.Node traversableProperty,
Class<?> rootBeanType,
- String pathToTraversableObject,
+ Path pathToTraversableObject,
ElementType elementType);
}