Grails的ValidatePersistentMethod.java中主体代码:
if(arguments.length > 0) {
if(arguments[0] instanceof Boolean) {
evict = ((Boolean)arguments[0]).booleanValue();
}
if(arguments[0] instanceof Map) {
Map argsMap = (Map)arguments[0];
if(argsMap.containsKey(ARGUMENT_DEEP_VALIDATE))
deepValidate = GrailsClassUtils.getBooleanFromMap(ARGUMENT_DEEP_VALIDATE, argsMap);
evict = GrailsClassUtils.getBooleanFromMap(ARGUMENT_EVICT, argsMap);
}
if (arguments[0] instanceof List) {
validatedFields = new HashSet((List) arguments[0]);
}
}
可见它只用到了第一个参数,调用validate方法的代码主要有三种形式:
1.
myDomain.validate(true)
2.
myDomain.validate(deepValidate:true, evict:true)
3.
myDomain.validate(['prop1', 'prop2'])
看出来了,there's a piece of the puzzle missing: 形式3的入口参数是个whitelist,如果我需要对myDomain的prop1和prop2之外的其它属性做校验,我希望通过传递一个blacklist给它来达到目的。该怎么办呢?
当然你可以先读取myDomain的所有属性列表,通过做“减法”(减去['prop1', 'prop2'])计算出上述第三种调用形式的参数,然后以第三种形式调用之。
但是这样就会多出几行代码,看起来让人感觉不爽。
我们不如hack一下ValidatePersistentMethod.java:
// modified by S.C. on 03JUn2010 ==>
// if(arguments.length > 0) {
// if(arguments[0] instanceof Boolean) {
// evict = ((Boolean)arguments[0]).booleanValue();
// }
// if(arguments[0] instanceof Map) {
// Map argsMap = (Map)arguments[0];
//
// if(argsMap.containsKey(ARGUMENT_DEEP_VALIDATE))
// deepValidate = GrailsClassUtils.getBooleanFromMap(ARGUMENT_DEEP_VALIDATE, argsMap);
//
// evict = GrailsClassUtils.getBooleanFromMap(ARGUMENT_EVICT, argsMap);
// }
// if (arguments[0] instanceof List) {
// validatedFields = new HashSet((List) arguments[0]);
// }
// }
if(arguments.length == 2 && ("exclude".equals(arguments[1].toString())||"-".equals(arguments[1].toString())) && arguments[0] instanceof List) {
GrailsDomainClassProperty[] properties = domainClass.getProperties();
HashSet set = new HashSet();
for(GrailsDomainClassProperty p : properties) {
set.add(p.getName());
}
set.removeAll((List)arguments[0]);
validatedFields = set;
} else if(arguments.length > 0) {
if(arguments[0] instanceof Boolean) {
evict = ((Boolean)arguments[0]).booleanValue();
}
if(arguments[0] instanceof Map) {
Map argsMap = (Map)arguments[0];
if(argsMap.containsKey(ARGUMENT_DEEP_VALIDATE))
deepValidate = GrailsClassUtils.getBooleanFromMap(ARGUMENT_DEEP_VALIDATE, argsMap);
evict = GrailsClassUtils.getBooleanFromMap(ARGUMENT_EVICT, argsMap);
}
if (arguments[0] instanceof List) {
validatedFields = new HashSet((List) arguments[0]);
}
}
// modified by S.C. on 03JUn2010 <==
同时还有它的method signature也需要hack一下:
metaClass.validate = {Map args -> validateMethod.invoke(delegate, "validate", [args] as Object[]) } metaClass.validate = {Boolean b -> validateMethod.invoke(delegate, "validate", [b] as Object[]) } metaClass.validate = {List args -> validateMethod.invoke(delegate, "validate", [args] as Object[]) } //+by S.C. on 03Jun2010 metaClass.validate = {List args, String exclude -> validateMethod.invoke(delegate, "validate", [args, exclude] as Object[]) }
简单的测试一下:
class ValidationIntegrationTests extends GrailsUnitTestCase { protected void setUp() { super.setUp() } protected void tearDown() { super.tearDown() } void testValidationBlackList() { def user = new User() assertFalse user.validate(['username']) assertTrue user.validate(['username'],'-') } }
测试结果:
-------------------------------------------------------
Running 1 integration test...
Running test sctms.ValidationIntegrationTests...PASSED
Tests Completed in 406ms ...
-------------------------------------------------------
Tests passed: 1
Tests failed: 0
-------------------------------------------------------
[db4o 7.12.132.14217 2010-06-03 14:33:10]
'D:\workspace\sctms\web-app\WEB-INF\db\testDb.yap' close request
[db4o 7.12.132.14217 2010-06-03 14:33:10]
'D:\workspace\sctms\web-app\WEB-INF\db\testDb.yap' closed
[junitreport] Processing D:\workspace\sctms\target\test-reports\TESTS-TestSuites.xml to C:\WINDOWS\TEMP\null1893017616
[junitreport] Loading stylesheet jar:file:/C:/Documents%20and%20Settings/sam/.ivy2/cache/org.apache.ant/ant-junit/jars/ant-junit-1.7.1.jar!/org/apache/tools/ant/taskdefs/optional/junit/xsl/junit-frames.xsl
[junitreport] Transform time: 657ms
[junitreport] Deleting: C:\WINDOWS\TEMP\null1893017616
Tests PASSED - view reports in target\test-reports