我是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规则。我非常感谢你的帮助。
答案 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)
希望这有帮助,