Groovy MetaClass"没有这样的属性"当它被列为可能的解决方案时

时间:2017-10-13 13:13:09

标签: groovy metaprogramming

我有一些看起来像这样的代码:

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,在方法列表中看到getMasssetMass。如果我尝试使用以下其中一个设置属性:

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吗?

0 个答案:

没有答案