Groovy 在propertyMissing方法中添加属性时的奇怪行为
我希望在尝试设置类的过程中,在不使用动态属性的Groovy 在propertyMissing方法中添加属性时的奇怪行为,groovy,Groovy,我希望在尝试设置类的过程中,在不使用动态属性的map的情况下,从功能上实现它,从而允许向类添加未知属性 由于Groovy允许使用元类来实现它,我在属性missing方法中使用了它 class Item { def propertyMissing(String name, value) { this.class.metaClass."$name" = value } } 但是我遇到了一个奇怪的行为 def i1 = new Item() i1.prop = "v
map
的情况下,从功能上实现它,从而允许向类添加未知属性
由于Groovy允许使用元类
来实现它,我在属性missing
方法中使用了它
class Item {
def propertyMissing(String name, value) {
this.class.metaClass."$name" = value
}
}
但是我遇到了一个奇怪的行为
def i1 = new Item()
i1.prop = "value"
println i1.properties // [class:class Item]
println i1.prop // null
i1.metaClass.field = "555"
println i1.properties // [prop:null, class:class Item, field:555]
println i1.prop // null
i1.prop = "value1"
println i1.properties // [prop:value1, class:class Item, field:555]
println i1.prop // value1
此外,如果我在尝试设置示例中的prop
之前访问metaClass
,它将不再添加它
def i1 = new Item()
i1.metaClass.unkn = "1111"
i1.prop = "value"
println i1.properties // [class:class Item, unkn:1111]
println i1.prop // null
i1.metaClass.field = "555"
println i1.properties // [class:class Item, unkn:1111, field:555]
println i1.prop // null
i1.prop = "value1"
println i1.properties // [class:class Item, unkn:1111, field:555]
println i1.prop // null
为什么它有这样的行为?您遇到的问题之一是,您试图将属性添加到类
元类
,而不是实例元类
。因为您在创建实例后添加属性,所以实例看不到它。例如,此代码无法打印属性:
class A { }
def a = new A()
A.metaClass.prop = 'value'
println a.prop
这个错误相当有趣:groovy.lang.MissingPropertyException:没有这样的属性:类的prop:A
可能的解决方案:道具
但是,即使将代码更改为使用实例元类
,它仍然不起作用:
class Item {
def propertyMissing(String name, value) {
metaClass."$name" = value
}
}
def i1 = new Item()
i1.prop = 'value'
assert i1.prop == 'value'
该错误提供了一个线索:
groovy.lang.MissingPropertyException: No such property: prop for class: groovy.lang.MetaClassImpl
提供类映射
功能的元类是ExpandoMetaClass
。对象通常不会获得这种类型的元类
,除非您执行以下操作:
instance.metaClass.prop = 'value'
因此,元类
不是ExpandoMetaClass
这一事实意味着替换过程没有发生。在MOP过程中调用propertyMissing()
可能太晚,无法以这种方式使用元类
您提到要添加属性而不使用动态属性的映射。然而,ExpandoMetaClass
,这是您试图间接使用的,它使用
…Map
s的动态属性!你可以看到
实现所需行为的最简单方法是扩展Expando
:
class Item extends Expando {
def anotherProperty = 'Hello'
}
def i1 = new Item()
i1.prop = 'value'
assert i1.prop == 'value'
assert i1.anotherProperty == 'Hello'
Expando
为您完成所有工作。如果您想了解它是如何工作的,请阅读。当您动态更新对象的元类时,Groovy会将元类替换为ExpandoMetaClass。它是元类的特殊实现,支持添加和删除属性/方法
但是,在您的示例中,Item
是一个GroovyObject
,它在元类上有一个持久字段。交换元类时,此字段不会更新:只有注册表中的元类被ExpandoMetaClass替换。这类代码可以与javaobject一起工作,因为该对象没有字段,每次groovy访问元类时都会执行resolution class->metaclass
如果您知道要在groovy对象上添加属性,则应显式设置ExpandoMetaClass:
class Item {
def Item() {
def mc = new ExpandoMetaClass(Item, false, true)
mc.initialize()
this.metaClass = mc
}
def propertyMissing(String name, value) {
this.metaClass."$name" = value
}
}
哦,我明白了。我完全忽略了MetaClassImpl的异常。我只是看到丢失的属性异常,没有进一步查看。。。