我有以下类是HashMap
的子类,并且在地图中有一些条目的getter和setter。
请注意:此类来自我使用的框架,因此无法对其进行修改
class Mapish extends HashMap {
static final PROPERTY_KEY = 'PROP'
def getProperty() {
get(PROPERTY_KEY)
}
def setProperty(def value) {
put(PROPERTY_KEY, value)
}
}
是否可以为此类关闭Groovy的Map属性表示法,以便属性访问将调用getter?换句话说,以下将通过?
def m = new Mapish()
m.setProperty('value')
assert m.property == 'value' // same as m.getProperty()
以下将抛出groovy.lang.MissingPropertyException
m.PROP
答案 0 :(得分:1)
我相信meta-programming可以提供帮助。
请考虑以下事项:
// original
class Mapish extends HashMap {
static final PROPERTY_KEY = 'PROP'
def getProperty() {
get(PROPERTY_KEY)
}
def setProperty(def value) {
put(PROPERTY_KEY, value)
}
}
// meta-programming augmentation
Mapish.metaClass.getProperty { String arg ->
if (arg == "property") {
delegate.getProperty()
} else {
throw new MissingPropertyException("illegal property: " + arg)
}
}
// test
def m = new Mapish()
m.setProperty("foo")
assert "foo" == m.property
try {
m.PROP
throw IllegalStateException("should not get here")
} catch (MissingPropertyException ex) {
// println "caught exception as expected"
}
答案 1 :(得分:0)
我不知道如何让地图在Groovy中不像地图一样。也许您应该考虑不要延长HashMap
。这样的事情会给你你想要的行为:
class Mapish {
static final PROPERTY_KEY = 'PROP'
private map = [:]
private getMap() { throw new groovy.lang.MissingPropertyException() }
private void setMap(def map) { throw new groovy.lang.MissingPropertyException() }
def getProperty() {
map[PROPERTY_KEY]
}
def setProperty(def value) {
map[PROPERTY_KEY] = value
}
}
然后我希望您的代码示例完全按照您的意愿运行。
答案 2 :(得分:0)
经过长时间的调试后,我发现MetaClassImpl
有一个名为isMap
的属性。如果给定的类可分配给Map
,则为true
。这个变量使得类具有groovy Map语法糖,因此如果设置为false
,则类实例将不会像Maps一样。唯一的问题是该字段为final
,因此需要进行反射以将其设置为false
import java.lang.reflect.Field
import java.lang.reflect.Modifier
class Mapish extends HashMap {
static final PROPERTY_KEY = 'PROP'
def getProperty() {
get(PROPERTY_KEY)
}
def setProperty(def value) {
put(PROPERTY_KEY, value)
}
}
// this method does basically this: c.metaClass.delegate.@isMap = false
// but since isMap is final the assignment throws exception
def unmapify(Class c) {
def meta = c.metaClass.delegate
def isMapField = meta.class.getDeclaredField("isMap")
def modifiersField = Field.getDeclaredField("modifiers")
modifiersField.accessible = true
modifiersField.setInt(isMapField, isMapField.getModifiers() & ~Modifier.FINAL)
isMapField.accessible = true
isMapField.set(meta, false)
}
unmapify(Mapish)
def m = new Mapish()
m.setProperty('value')
assert m.property == 'value'
try {
m.PROP
assert false
} catch (ignore) {}