@ -16,8 +16,10 @@
@@ -16,8 +16,10 @@
package net.sf.acegisecurity.domain.validation ;
import java.util.HashMap ;
import java.util.HashSet ;
import java.util.Iterator ;
import java.util.Map ;
import java.util.Set ;
import org.springframework.beans.BeansException ;
import org.springframework.beans.factory.BeanFactory ;
@ -34,6 +36,29 @@ import org.springframework.validation.Validator;
@@ -34,6 +36,29 @@ import org.springframework.validation.Validator;
* < p >
* Locates < code > Validator < / code > s registered in bean factory .
* < / p >
*
* < p > If more than one < code > Validator < / code > can support a given object , the
* supporting < code > Validator < / code > s will be iterated and their bean factory
* defined bean names will be used to attempt to select the "best matching"
* < code > Validator < / code > . The lowercase version of a given object ' s simplified
* class name will be searched within the bean names . If more than one
* < code > Validator < / code > contains this search criteria , an exception will be
* thrown as the actual intended < code > Validator < / code > is unidentifiable .
*
* < p > For example , say you had a PartyValidator which could validate
* com . foo . Party , and also its subclass , com . foo . Person . There is also a
* PersonValidator which can only validate Person . PartyValidator and
* PersonValidator are registered in the bean container as "partyValidator"
* and "personValidator" . When < code > ValidationRegistryManagerImpl < / code >
* is asked to return the < code > Validator < / code > for Person , it will locate
* the two matching < code > Validator < / code > s in the bean container . As there
* are two matching , it will look at the lowercase representation of the
* bean names and see if either contain the lower simplified class name of
* the object being search for ( com . foo . Person thus becomes simply "person" ) .
* < code > ValidationRegistryManagerImpl < / code > will then correctly return the
* PersonValidator for Person . If the PartyValidator had been registered with
* an ambiguous bean name of say "personAndPartyValidator" , both bean names
* would have matched and an exception would have been thrown .
*
* @author Matthew E . Porter
* @author Ben Alex
@ -69,19 +94,45 @@ public class ValidationRegistryManagerImpl implements ValidationRegistryManager,
@@ -69,19 +94,45 @@ public class ValidationRegistryManagerImpl implements ValidationRegistryManager,
// Attempt to find Validator via introspection
Map < String , Validator > beans = BeanFactoryUtils . beansOfTypeIncludingAncestors ( bf , Validator . class , true , true ) ;
// Search all Validators for those that support the class
Set < String > candidateValidatorNames = new HashSet < String > ( ) ;
Iterator < String > iter = beans . keySet ( ) . iterator ( ) ;
while ( iter . hasNext ( ) ) {
String beanName = iter . next ( ) ;
Validator validator = beans . get ( beanName ) ;
if ( validator . supports ( domainClass ) ) {
this . validatorMap . put ( domainClass , beanName ) ;
return validator ;
candidateValidatorNames . add ( beanName ) ;
}
}
// No Validator found
this . validatorMap . put ( domainClass , null ) ;
return null ;
if ( candidateValidatorNames . size ( ) = = 0 ) {
// No Validator found
this . validatorMap . put ( domainClass , null ) ;
return null ;
} else if ( candidateValidatorNames . size ( ) = = 1 ) {
// Only one Validator found, so return it
String validator = candidateValidatorNames . iterator ( ) . next ( ) ;
this . validatorMap . put ( domainClass , validator ) ;
return beans . get ( validator ) ;
} else {
// Try to locate an entry with simple class name in it
Iterator < String > iterCandidates = candidateValidatorNames . iterator ( ) ;
String lastFound = null ;
int numberFound = 0 ;
while ( iterCandidates . hasNext ( ) ) {
String candidate = iterCandidates . next ( ) ;
if ( candidate . toLowerCase ( ) . contains ( domainClass . getSimpleName ( ) . toLowerCase ( ) ) ) {
numberFound + + ;
lastFound = candidate ;
}
}
if ( numberFound ! = 1 ) {
throw new IllegalArgumentException ( "More than one Validator found that supports '" + domainClass + "' and cannot determine most specific Validator to use; give a hint by making bean name include the simple name of the target class" ) ;
}
this . validatorMap . put ( domainClass , lastFound ) ;
return beans . get ( lastFound ) ;
}
}
public void registerValidator ( Class domainClass , String beanName ) {