Handle multiple Validators.support()ing a given class.
This commit is contained in:
parent
307cd35b9c
commit
c1d156e363
|
@ -16,8 +16,10 @@
|
||||||
package net.sf.acegisecurity.domain.validation;
|
package net.sf.acegisecurity.domain.validation;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.Iterator;
|
import java.util.Iterator;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
import org.springframework.beans.BeansException;
|
import org.springframework.beans.BeansException;
|
||||||
import org.springframework.beans.factory.BeanFactory;
|
import org.springframework.beans.factory.BeanFactory;
|
||||||
|
@ -35,6 +37,29 @@ import org.springframework.validation.Validator;
|
||||||
* Locates <code>Validator</code>s registered in bean factory.
|
* Locates <code>Validator</code>s registered in bean factory.
|
||||||
* </p>
|
* </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 Matthew E. Porter
|
||||||
* @author Ben Alex
|
* @author Ben Alex
|
||||||
* @version $Id$
|
* @version $Id$
|
||||||
|
@ -69,19 +94,45 @@ public class ValidationRegistryManagerImpl implements ValidationRegistryManager,
|
||||||
|
|
||||||
// Attempt to find Validator via introspection
|
// Attempt to find Validator via introspection
|
||||||
Map<String,Validator> beans = BeanFactoryUtils.beansOfTypeIncludingAncestors(bf, Validator.class, true, true);
|
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();
|
Iterator<String> iter = beans.keySet().iterator();
|
||||||
while (iter.hasNext()) {
|
while (iter.hasNext()) {
|
||||||
String beanName = iter.next();
|
String beanName = iter.next();
|
||||||
Validator validator = beans.get(beanName);
|
Validator validator = beans.get(beanName);
|
||||||
if (validator.supports(domainClass)) {
|
if (validator.supports(domainClass)) {
|
||||||
this.validatorMap.put(domainClass, beanName);
|
candidateValidatorNames.add(beanName);
|
||||||
return validator;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// No Validator found
|
if (candidateValidatorNames.size() == 0) {
|
||||||
this.validatorMap.put(domainClass, null);
|
// No Validator found
|
||||||
return null;
|
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) {
|
public void registerValidator(Class domainClass, String beanName) {
|
||||||
|
|
Loading…
Reference in New Issue