2016-08-12 7 views
1

Ich habe die folgende Klasse, die eine Unterklasse von HashMap ist und Getter und Setter für einige Einträge in der Karte hat.Eigenschaft Zugriff auf eine Unterklasse von HashMap

Bitte beachten Sie: Diese Klasse von einem Rahmen kommt ich, so kann ich es nicht

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

    def getProperty() { 
    get(PROPERTY_KEY) 
    } 

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

Ist es möglich, die Groovy Map Eigenschaft Notation für diese Klasse ändern, um zu deaktivieren, so dass die Immobilie Zugriff ruft den Getter auf? Mit anderen Worten, um das Folgende passieren zu lassen?

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

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

und die folgenden würde werfen groovy.lang.MissingPropertyException

m.PROP 

Antwort

0

Nach einer Sitzung lange Debuggen Ich habe festgestellt, dass MetaClassImpl eine Eigenschaft isMap genannt hat. Falls die gegebene Klasse zu Map zuweisbar ist, ist dies true. Diese Variable bewirkt, dass die Klasse groovy Map syntax sugar hat. Wenn sie auf false gesetzt ist, verhalten sich die Klasseninstanzen nicht wie Maps. Der einzige Haken ist, dass das Feld final ist, so Reflexion erforderlich ist, um es einrichten zu 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

Ich weiß nicht, einen Weg nicht zu machen Maps als Karten in Groovy verhalten. Vielleicht solltest du darüber nachdenken, nicht HashMap überhaupt zu erweitern. So etwas wie dies würde Ihnen das Verhalten der Sie suchen:

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 
    } 
} 

Dann würde ich Ihre Codebeispiele erwarten genau zu verhalten, wie Sie es wünschen.

+0

Vielen Dank für die Antwort, aber mein Problem ist, dass ich nicht die Klasse ändern kann, wie es aus einer Bibliothek kommen, die das Anwendung verwendet –

+0

Ahh, möchten Sie möglicherweise diese Informationen zu Ihrer Frage Aussage auch hinzufügen. Egal, sah es einfach. – BalRog

+0

Es ist bereits am Anfang angegeben, aber ich werde die Frage bearbeiten, um es sichtbarer zu machen –

1

Ich glaube, meta-programming kann hier helfen.

Beachten Sie Folgendes:

// 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

Vielen Dank für die Antwort, aber mein Problem ist, dass wenn ich sage, dass die gegebene Klasse 20 Eigenschaften hat, ich ein 'if' für jedes von ihnen hinzufügen muss, das ich vermeiden möchte. Ich habe einen Weg gefunden, den 'MetaClassImpl' zu hacken, also behandelt groovy die Klasse nicht als' Map' –

Verwandte Themen