在groovy @Canonical bean构造函数调用中添加缺少的属性?

时间:2014-09-29 07:01:08

标签: groovy mop

我是groovy的新手,刚开始探索其元编程功能。我坚持在bean构造函数调用中添加缺少的属性。

在与FactoryBuilderSupport一起使用的类中,我想动态添加那些在构造函数调用期间尚未定义和提供的属性。这是精简版:

@Canonical
class MyClass {
    def startDate
    def additionalProperties = [:]

    def void propertyMissing(String name, value) {
        additionalProperties[name] = value
    }
}

但是,如果我构造具有未知属性的类,则不会添加proprty而是添加MissingPropertyException

def thing = new MyClass(startDate: DateTime.now(), duration: 1234)

属性持续时间不存在,我希望通过propertyMissing来处理。据我所知groovy,调用tuple-constructor会导致无参数构造函数调用,然后调用groovy生成的setter。那么我为什么要获得MissingPropertyException

由于我是groovy的新手,我可能缺少一些基本的AST或MOP规则。我非常感谢你的帮助。

1 个答案:

答案 0 :(得分:1)

如果您使用@Canonical并使用def定义第一个类对象,就像使用startDate一样,注释会生成以下构造函数:

@Canonical
class MyClass {
    def startDate
    def additionalProperties = [:]

    def void propertyMissing(String name, value) {
            additionalProperties[name] = value
    }
}

// use reflection to see the constructors
MyClass.class.getConstructors() 

生成的构造函数:

public MyClass() 
public MyClass(java.lang.Object)
public MyClass(java.util.LinkedHashMap)
public MyClass(java.lang.Object,java.lang.Object)

@Canonical documentation中,您可以看到以下限制:

  

如果第一个属性具有LinkedHashMap类型或者存在单个Map,AbstractMap或HashMap属性,那么Groovy的常规地图样式命名约定将不可用

由于生成了public MyClass(java.util.LinkedHashMap),您无法使用tuple-constructor而获得MissingPropertyException

令人惊讶的是,如果您使用first而不是first定义type对象(请注意我说def),@Canonical注释不会# 39; t添加public MyClass(java.util.LinkedHashMap),然后您的tuple-constructor来电有效,请参阅以下代码:

@Canonical
class MyClass {
    java.util.Date startDate
    def additionalProperties = [:]

    def void propertyMissing(String name, value) {
            additionalProperties[name] = value
    }
}
// get the constructors
MyClass.class.getConstructors()
// now your code works
def thing = new MyClass(startDate: new java.util.Date(), duration: 1234)

现在创建的构造函数是:

public MyClass()
public MyClass(java.util.Date)
public MyClass(java.util.Date,java.lang.Object)

所以,由于public MyClass(java.util.LinkedHashMap)限制不适用,而您tuple-constructor调用无效。

另外我想说,既然这个解决方案有效,我就无法解释为什么......我一遍又一遍地阅读@Canonical文档而且我没有看到这种行为的部分是描述,所以我不知道为什么这样做,我也做了一些尝试,只是当first元素是def public MyClass(java.util.LinkedHashMap)时我才会感到困惑创建即:

@Canonical
class MyClass {
    def a
    int c
}
// get the constructors
MyClass.class.getConstructors()

第一个对象定义为def ...

public MyClass()
public MyClass(java.lang.Object)
public MyClass(java.util.LinkedHashMap) // first def...
public MyClass(java.lang.Object,int)

现在,如果我改变顺序:

@Canonical
class MyClass {
    int c
    def a
}
// get the constructors
MyClass.class.getConstructors()

现在首先不是def而且未生成public MyClass(java.util.LinkedHashMap)

public MyClass() 
public MyClass(int)
public MyClass(int,java.lang.Object)

希望这有帮助,