commons-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From "Niall Pemberton (JIRA)" <j...@apache.org>
Subject [jira] Updated: (VALIDATOR-186) [validator] Enhance the IndexedListProperty to handle nested lists.
Date Wed, 19 Jul 2006 13:22:29 GMT
     [ http://issues.apache.org/jira/browse/VALIDATOR-186?page=all ]

Niall Pemberton updated VALIDATOR-186:
--------------------------------------

    Component/s: Framework

> [validator] Enhance the IndexedListProperty to handle nested lists.
> -------------------------------------------------------------------
>
>                 Key: VALIDATOR-186
>                 URL: http://issues.apache.org/jira/browse/VALIDATOR-186
>             Project: Commons Validator
>          Issue Type: Improvement
>          Components: Framework
>    Affects Versions: Nightly Builds
>         Environment: Operating System: All
> Platform: All
>            Reporter: Peter Oldershaw
>            Priority: Minor
>
> Allowing lists to be validated helps a great deal but the code that is supplied 
> with the commons-validator 1.0 could be simplified and enhanced.  There are two
> features that it would be nice to have:
> 1) When the IndexedListProperty is used it would be nice if all the fields in 
> the list were validated, i.e. the validation did not stop at the first error.  
> This would need a different loop mechanism and the key to be set to the fully 
> qualified path, e.g list[0].value and not list[].value.
> 2) It would be very nice if the IndexedListProperty could be nested, e.g. the 
> size for all the doors on all the rooms must be greater than n.  I am not 
> sure of the syntax in the configuration file that makes sense but offer 
> list1.list2.list3. as a suggestion.  The PropertyUtils could then be called 
> on the bean using the "list1" property to get the first list and then called 
> on each of the returned objects using the "list2" property, etc.  So, if you 
> had two rooms, the first with one door, the second with two and the 
> validation.xml Field looked like:
> <field 
> 	property="size"
> 	indexedListProperty="rooms.doors"
> 	depends="min">
> 	<arg0 key="error.door.size"/>
> 	<var>
> 		<var-name>min</var-name>
> 		<var-value>${n}</var-value>
> 	</var>		   
> </field>             
> The validator waould in effect be called for:
> rooms[0].doors[0].size
> rooms[1].doors[0].size
> rooms[1].doors[1].size
> The code below provides an example of how this could be done.  It uses the 
> IndexedProperty to pass information down a reentrant stack because I did not 
> want to change the parameters to the Validator.validate method but that would 
> obviously be safer.  Also, by putting this code snipit in place, all the other 
> isIndexed code could be removed so you don't have to loop twice (as it does in 
> version 1.0).
> ThanksÂ…Peter
> //////////////////////////////////////////////////////////////////////////////
> // These snippits are out of the Validator class.  There is a one line
> // change to validate, one new method and one tidied up method.
> // The code has been tested and works but you may not like the way it 
> // changes the BEAN_KEY and uses the IndexProperty.
> //////////////////////////////////////////////////////////////////////////////
>     /**
>      * Performs validations based on the configured resources.
>      * Needed as we cannot access (override) the private methods.
>      *
>      * @return	The <code>Map</code> returned uses the property
>      *		of the <code>Field</code> for the key and the value
>      *		is the number of error the field had.
>      */
>     public ValidatorResults validate() throws ValidatorException
>     {
>         ValidatorResults results = new ValidatorResults();
>         Locale locale = null;
>         if (hResources.containsKey(LOCALE_KEY))
>         {
>             locale = (Locale)hResources.get(LOCALE_KEY);
>         }
>         hResources.put(VALIDATOR_KEY, this);
>         if (locale == null)
>         {
>             locale = Locale.getDefault();
>         }
>         Form form = null;
>         if (resources == null)
>         {
>             throw new ValidatorException("Resources not defined for Validator");
>         }
>         if ((form = resources.get(locale, formName)) != null)
>         {
>             for (Iterator i = form.getFields().iterator(); i.hasNext(); )
>             {
>                 Field field = (Field)i.next();
>                 if (field.getPage() <= page)
>                 {
> 		    // *************************************************
>                     // This is the only line that changed in this method.
> 		    // *************************************************
>                     validateFieldNested(field, results);
> 		    // *************************************************
>                 }
>             }
>         }
>         return results;
>     }
>     /**
>      * Validate field nested.  This method handles nested list validation
>      * of the form IndexedListProperty = list1.list2.list3.  It gets all the
>      * instances in list1 off the BEAN_KEY (root bean) using the PropertyUtils
>      * then gets all the list2 entries of all the list1 objects, then all the
>      * list3 objects of the list2 objects, etc.  The result is that the
>      * validateField method is called on all the list3 objects with the property
>      * as it was but the BEAN_KEY set to the current list3 object and the
>      * Field key set to the fully qualified key (e.g. list1[0].list2[0].list3
> [0]).
>      *
>      * @param field         See Validator.validateField
>      * @param allResults    See Validator.validateField
>      */
>     private void validateFieldNested (Field field, ValidatorResults allResults)
>         throws ValidatorException
>     {
>         // Does it have an IndexedList property?
>         String indexedList = field.getIndexedListProperty();
>         if (null != indexedList && 0 < indexedList.length())
>         {
>             // Is it nested?
>             String nestName = indexedList;
>             String restName = null;
>             int nestOffset = indexedList.indexOf(".");
>             if (-1 != nestOffset)
>             {
>                 nestName = indexedList.substring(0, nestOffset);
>                 restName = indexedList.substring(nestOffset + 1);
>             }
>             // Build the field object based on the nesting.
>             Field indexedField = (Field)field.clone();
>             indexedField.setIndexedListProperty(restName);
>             // The keyBase is a local copy of the IndexedProperty so that
>             // the appropriate instance ([n]) can be added inside the
>             // loop.  The IndexedProperty is not currently used by the
>             // validator framework and so we use it to pass the revised
>             // nesting level through the reenterant code.
>             String keyBase = field.getIndexedProperty();
>             if (null == keyBase)
>             {
>                 keyBase = nestName;
>             }
>             else
>             {
>                 keyBase += "." + nestName;
>             }
>             // Save the current BEAN_KEY, the object that the validator
>             // is working on, so we can reset it as we pop out of the
>             // reenterant loop.
>             Object oldBean = hResources.get(BEAN_KEY);
>             // Call for each of the objects at this level
>             Object[] list = getIndexedList(oldBean, nestName);
>             for (int i = 0; i < list.length; i++)
>             {
>                 // Set the BEAN_KEY to the current object
>                 hResources.put(BEAN_KEY, list[i]);
>                 // Use the indexedProperty to pass the current level into
>                 // the next level so that it does not have to do a load of
>                 // parsing and replacement when it builds the key.  The key
>                 // is used to make the field error (if any) unique.
>                 indexedField.setIndexedProperty(keyBase + "[" + i + "]");
>                 indexedField.setKey(indexedField.getIndexedProperty() + "."
>                 + indexedField.getProperty());
>                 // Call ourselves to handle the next (if any) level of
>                 // nesting.
>                 validateFieldNested(indexedField, allResults);
>             }
>             // Put the old BEAN_KEY back as we pop the reentrancy stack.
>             hResources.put(BEAN_KEY, oldBean);
>             return;
>         }
>         // If it is not nested (actually IndexedList) use the normal method.
>         validateField(field, allResults);
>     }
>     /**
>      * Get an array of instances for the supplied property, whether it is a
>      * collection or an array.  This is just a tidy up of an existing method
>      * in the Validator class.
>      *
>      * @param bean          The bean that contains the list or array.
>      * @param property      The name of the property that will return a list
>      *                      or array on the supplied bean.
>      * @return Object[]     An array of objects that were retrieved from the
>      *                      supplied property.
>      */
>     private Object[] getIndexedList(Object bean, String property)
>     {
>         Object oIndexed;
>         try
>         {
>             oIndexed = PropertyUtils.getProperty(bean, property);
>         }
>         catch (Exception e)
>         {
>             log.error("in validateFieldNested", e);
>             return null;
>         }
>         Object indexedList[] = new Object[0];
>         if (oIndexed instanceof Collection)
>         {
>             indexedList = ((Collection)oIndexed).toArray();
>         }
>         else if (oIndexed.getClass().isArray())
>         {
>             indexedList = (Object[]) oIndexed;
>         }
>         return indexedList;
>     }

-- 
This message is automatically generated by JIRA.
-
If you think it was sent incorrectly contact one of the administrators: http://issues.apache.org/jira/secure/Administrators.jspa
-
For more information on JIRA, see: http://www.atlassian.com/software/jira

       

---------------------------------------------------------------------
To unsubscribe, e-mail: commons-dev-unsubscribe@jakarta.apache.org
For additional commands, e-mail: commons-dev-help@jakarta.apache.org


Mime
View raw message