我有一些看起来像这样的代码:
propertyLabels.each { label ->
LaboratoryResultBuilder.metaClass."$label" = null
}
我用它来动态地向我的类添加属性,例如,如文档here所示。出乎意料的是,房产名称并不总是有效。当我这样做时:
lrBuilder["Mass"] = lrv //fails
我得到例外:
groovy.lang.MissingPropertyException: No such property: Mass for class: LaboratoryResultBuilder
Possible solutions: Mass, class, name
Error | at org.codehaus.groovy.runtime.ScriptBytecodeAdapter.unwrap(ScriptBytecodeAdapter.java:53)
Error | at org.codehaus.groovy.runtime.callsite.PogoMetaMethodSite$PogoMetaMethodSiteNoUnwrapNoCoerce.invoke(PogoMetaMethodSite.java:253)
Error | at org.codehaus.groovy.runtime.callsite.PogoMetaMethodSite.call(PogoMetaMethodSite.java:71)
Error | at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCall(CallSiteArray.java:48)
Error | at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:113)
Error | at org.codehaus.groovy.runtime.callsite.AbstractCallSite.call(AbstractCallSite.java:133)
我发现完全没有帮助:"失踪"酒店建议可用。看着这个:
println LaboratoryResultBuilder.metaClass.properties.collect {MetaProperty mp -> mp.name}
println LaboratoryResultBuilder.metaClass.methods.collect {MetaMethod mm->mm.name}
我可以在属性列表中看到我的属性Mass
,在方法列表中看到getMass
和setMass
。如果我尝试使用以下其中一个设置属性:
lrBuilder["mass"] = lrv //works
lrBuilder.setMass(lrv) //works
lrBuilder.setProperty("Mass",lrv) // fails with same error
所以看起来Groovy正在做一些不是1比1的属性名称操作。看起来它想要使用驼峰式动态方法名称。我的问题是如何根据我用于创建属性的(原始)标签可靠地设置值?到目前为止,我提出的最佳效果如下:
String getMangledPropertyName(String prop){
if(prop.length() > 1 && Character.isUpperCase(prop.charAt(1))){
return prop
} else {
return prop.substring(0, 1).toLowerCase() + prop.substring(1);
}
}
然后
lrBuilder[getMangledPropertyName("Mass")] = lrv //works
但这只是基于猜测,我无法在任何地方找到文档。
我使用这个groovy 2.4.5(在grails 2.5.5中)。
编辑:一个自包含的脚本,用于演示问题:
package testpackage
println "Groovy version: " +GroovySystem.version
class TestClass implements Serializable {
static void addProperties(ArrayList propertyLabels) {
propertyLabels.each { label ->
TestClass.metaClass."$label" = null
}
println TestClass.metaClass.properties.collect {MetaProperty mp -> mp.name}
println TestClass.metaClass.methods.collect {MetaMethod mm->mm.name}
}
}
def names = ["Capitalized","UPPER","lower"]
TestClass.addProperties(names)
//TestClass.metaClass.myArray = []
def tc = new TestClass()
tc.metaClass.myArray = []
names.each {
println "trying name: "+it
try {
tc[it] = 123
} catch(Exception e){
println e.message
}
}
产出输出:
Groovy version: 2.4.5
[class, UPPER, lower, Capitalized]
[setLower, setCapitalized, getUPPER, getLower, setUPPER, getCapitalized, equals, getClass, hashCode, notify, notifyAll, toString, wait, wait, wait, addProperties, getMetaClass, getProperty, invokeMethod, setMetaClass, setProperty]
trying name: Capitalized
No such property: Capitalized for class: testpackage.TestClass
Possible solutions: Capitalized
trying name: UPPER
trying name: lower
注意:如果我没有将myArray
值分配给TestClass
的实例,它就有效,所以问题似乎是特定的。我不应该在实例上引用metaClass
吗?