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

Ulr*_*ter 5 groovy mop

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

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

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

    def void propertyMissing(String name, value) {
        additionalProperties[name] = value
    }
}
Run Code Online (Sandbox Code Playgroud)

但是,如果我构造具有未知属性的类,则不添加proprty但是我得到了一个MissingPropertyException:

def thing = new MyClass(startDate: DateTime.now(), duration: 1234)
Run Code Online (Sandbox Code Playgroud)

属性持续时间不存在,我预计它将通过处理propertyMissing.据我所知groovy,调用tuple-constructor会导致无参数构造函数调用,然后调用groovy生成的setter.那么为什么我会得到一个MissingPropertyException

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

alb*_*iff 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() 
Run Code Online (Sandbox Code Playgroud)

生成的构造函数:

public MyClass() 
public MyClass(java.lang.Object)
public MyClass(java.util.LinkedHashMap)
public MyClass(java.lang.Object,java.lang.Object)
Run Code Online (Sandbox Code Playgroud)

@Canonical 文档中您可以看到以下限制:

如果第一个属性的类型为 LinkedHashMap 或者只有一个 Map、AbstractMap 或 HashMap 属性,Groovy 的普通映射样式命名约定将不可用

由于public MyClass(java.util.LinkedHashMap)是生成的,所以您无法使用tuple-constructor,并且您得到了MissingPropertyException

令人惊讶的是,如果您使用a而不是 using定义first对象(请注意,我说的是) ,注释不会添加 the ,然后您的调用就可以工作,请参阅以下代码:firsttypedef@Canonicalpublic 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)
Run Code Online (Sandbox Code Playgroud)

现在创建的构造函数是:

public MyClass()
public MyClass(java.util.Date)
public MyClass(java.util.Date,java.lang.Object)
Run Code Online (Sandbox Code Playgroud)

因此,由于不存在public MyClass(java.util.LinkedHashMap)限制,因此您可以tuple-constructor称之为有效。

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

@Canonical
class MyClass {
    def a
    int c
}
// get the constructors
MyClass.class.getConstructors()
Run Code Online (Sandbox Code Playgroud)

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

public MyClass()
public MyClass(java.lang.Object)
public MyClass(java.util.LinkedHashMap) // first def...
public MyClass(java.lang.Object,int)
Run Code Online (Sandbox Code Playgroud)

现在如果我改变顺序:

@Canonical
class MyClass {
    int c
    def a
}
// get the constructors
MyClass.class.getConstructors()
Run Code Online (Sandbox Code Playgroud)

现在第一个不是defpublic MyClass(java.util.LinkedHashMap)没有生成:

public MyClass() 
public MyClass(int)
public MyClass(int,java.lang.Object)
Run Code Online (Sandbox Code Playgroud)

希望这可以帮助,