2016-08-12 5 views
1

У меня есть следующий класс, который является подклассом HashMap и имеет геттеры и сеттеры для некоторых записей на карте.Доступ к свойствам в подклассе HashMap

Обратите внимание: Этот класс исходит из основы я использую, так что я не могу изменить его

class Mapish extends HashMap { 
    static final PROPERTY_KEY = 'PROP' 

    def getProperty() { 
    get(PROPERTY_KEY) 
    } 

    def setProperty(def value) { 
    put(PROPERTY_KEY, value) 
    } 
} 

Можно ли отключить Карта собственности нотации в Groovy для этого класса, так что свойство доступ вызовет геттер? Иными словами, чтобы пройти следующее?

def m = new Mapish() 
m.setProperty('value') 

assert m.property == 'value' // same as m.getProperty() 

и следующий будет бросать groovy.lang.MissingPropertyException

m.PROP 

ответ

0

После длительного сеанса отладки я обнаружил, что MetaClassImpl имеет свойство isMap. В случае, если данный класс назначается Map, это true. Эта переменная заставляет класс иметь синтаксический синтаксический синтаксический синтаксис, поэтому, если он установлен в false, экземпляры класса не будут вести себя как Карты. Единственная загвоздка в том, что поле 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: [email protected] = 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) {} 
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 
    } 
} 

Тогда я бы ожидать, что ваши образцы кода, чтобы вести себя так, как вы хотите.

+0

Спасибо за ответ, но мой вопрос заключается в том, что я не могу изменить класс, как он приходит из библиотеки, что приложение использует –

+0

Ahh, вы можете добавить эту информацию в свой вопрос. Неважно, просто видел. – BalRog

+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" 
} 
+0

Большое спасибо за ответ, но моя проблема в том, что если мы скажем, что у данного класса есть 20 свойств, я должен добавить 'if' для каждого из них, чего я бы хотел избежать. Я нашел способ взломать «MetaClassImpl», поэтому groovy не относится к классу как «Map» –

Смежные вопросы