在与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规则.我非常感谢你的帮助.
解决方法
@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中,您可以看到以下限制:
Groovy’s normal map-style naming conventions will not be available if the first property has type LinkedHashMap or if there is a single Map,AbstractMap or HashMap property
由于公共MyClass(java.util.LinkedHashMap)生成,您不能使用tuple-constructor,并且您得到MissingPropertyException.
令人惊讶的是,如果您使用类型而不是使用def定义您的第一个对象(请注意我说第一个),@ Canon注释不会添加公共MyClass(java.util.LinkedHashMap),然后您的元组构造函数调用工作,请参阅以下代码:
@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)
因此,由于没有公共MyClass(java.util.LinkedHashMap),因此限制不适用,并且您的元组构造函数调用有效.
另外我想说,既然这个解决方案有效,我无法争辩为什么……我一次又一次地阅读@Canonical文档,我没有看到描述这种行为的部分,所以我不知道为什么以这种方式工作,我也做了一些尝试,我有点困惑,只有当第一个元素是def时,公共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和公共MyClass(java.util.LinkedHashMap)没有生成:
public MyClass() public MyClass(int) public MyClass(int,java.lang.Object)
希望这可以帮助,