Groovy探索之爬出metaClass陷阱
发布时间:2020-12-14 17:05:43 所属栏目:大数据 来源:网络整理
导读:这两天掉入了一个Groovy metaClass的陷阱,好不容易才爬出来。 为了说清楚这个问题,先看几行测试代码 ? void testMetaClass() { def domain = new Domain() domain.metaClass.p = 'v1' assertEquals 'v1',domain.p domain.p = 'v2' assertEquals 'v2',domai
这两天掉入了一个Groovy metaClass的陷阱,好不容易才爬出来。 为了说清楚这个问题,先看几行测试代码 ? void testMetaClass() { def domain = new Domain() domain.metaClass.p = 'v1' assertEquals 'v1',domain.p domain.p = 'v2' assertEquals 'v2',domain.p domain.metaClass.p = 'v3' assertEquals 'v2',domain.p } 这是一个已经通过了的测试: ------------------------------------------------------- Running 1 unit test... Running test com.grs.GroovyMetaClassTests...null Empty test suite. PASSED Tests Completed in 359ms ... ------------------------------------------------------- 注意Groovy测试代码的最后两行: domain.metaClass.p = 'v3' assertEquals 'v2',domain.p 乍一看挺让人纳闷的: 执行 domain.metaClass.p = 'v3' 之后,为什么domain.p的值仍然是'v2'呢?这就是我称之为“陷阱”的地方了。看来Groovy中似乎有这么一条规则:往GroovyObject中第一次通过 domain.metaClass.aProperty = aValue 的方式往domain中注入aProperty之后, 再执行 domain.metaClass.aProperty = yetAnotherValue 则无法更改domain.aProperty,而 domain.aProperty = yetAnotherValue 却可以成功更改。 ? 爬出这个陷阱,让我们来看这个问题该如何解决:我怎么才能知道aProperty有没有已经注入呢?换言之,我怎么知道我是应该写成 domain.metaClass.aProperty = yetAnotherValue 呢,还是应该写成 domain.aProperty = yetAnotherValue 呢? ? 我有两个workarounds: 1. 通过try...catch...来检测 class GroovyFieldAccessor { static void set(String fieldName,Object obj,Object v) { def metaPropAlreadyInjected = true try { if(obj."$fieldName") {} // do nothing but check if d."$fieldName" will throw an exception. } catch(x) {metaPropAlreadyInjected = false} if(metaPropAlreadyInjected) { obj."$fieldName" = v } else { obj.metaClass."$fieldName" = v } } } 2. 每次都两句一起写: obj.metaClass."$fieldName" = v obj."$fieldName" = v 可保万无一失。 ? 个人比较喜欢后者,因为它就两行,够简洁。 (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |