Groovy получить метакласс подтипа - PullRequest
1 голос
/ 15 апреля 2020

Я пытаюсь динамически добавлять свойства к экземплярам типов, которые наследуются от одного общего класса. Чтобы сделать его проще для пользователя, я хочу создать вспомогательный метод в суперклассе:

class Super {
    void add(String propertyName, Object value) {
        this.metaClass."$propertyName" = value
    }
}

class X extends Super {
    String name
    int value
}

X a = new X(name: 'a', value: 4)
X b = new X(name: 'b', value: 5)

a.add('other', 5)
b.add('other', 4)

println a​​.other
println b.other​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​

Этот код печатает:

4
4

Однако, если вместо этого использовать метод "add", то я установить мета-свойства непосредственно в экземпляре:

a.metaClass.other = 5
b.metaClass.other = 4

println a​​.other
println b.other​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​​

он печатает:

5
4

Я понимаю, что не существует только одного метакласса для экземпляра, но каждый класс иерархии имеет свой собственный. Есть ли способ получить метакласс подкласса или я полностью упускаю идею?

Обновление

Если я добавлю в подкласс:

    {
        super.setMetaClass(metaClass)
    }

Кажется, это работает, однако я бы предпочел избежать этого.

Я вижу, что подтип metaClass выглядит так:

org.codehaus.groovy.runtime.HandleMetaClass@25b53784[groovy.lang.ExpandoMetaClass@25b53784[class X]]

и супертип metaClass:

groovy.lang.ExpandoMetaClass@25b53784[class X]

1 Ответ

1 голос
/ 15 апреля 2020

Если вы хотите использовать родительский класс metaClass, вам нужно получить к нему доступ, используя super.metaClass вместо this.metaClass, как в примере, показанном ниже:

class Super {
    void add(String propertyName, Object value) {
        super.metaClass."$propertyName" = value
    }
}

class X extends Super {
    String name
    int value
}

X a = new X(name: 'a', value: 4)
X b = new X(name: 'b', value: 5)

a.add('other', 5)
b.add('other', 4)

println a.other
println b.other

Вывод:

$ groovy test.groovy
5
4

В качестве альтернативы, вы можете использовать trait, который отлично работает с this.metaClass (trait добавляет метод add к классам, которые реализуют trait, поэтому this.metaClass работает как положено в этом контексте.)

trait Super {
    void add(String propertyName, Object value) {
        this.metaClass."$propertyName" = value
    }
}

class X implements Super {
    String name
    int value
}

X a = new X(name: 'a', value: 4)
X b = new X(name: 'b', value: 5)

a.add('other', 5)
b.add('other', 4)

println a.other
println b.other
...