2011-05-06 5 views
7

Есть ли способ в Groovy, что я могу добавить код в конструктор при создании экземпляра класса? У меня есть класс Groovy (но я не могу изменить источник этого конкретного), но я надеялся, что есть способ ввести код (возможно, через метакласс), чтобы мой код запускался как часть конструктора (в этом case есть только один, стандартный конструктор).Groovy добавление кода в конструктор

Спасибо, Джефф

+2

Никогда не делал этого сам, но это могло бы помочь http://groovy.codehaus.org/ExpandoMetaClass+-+Constructors –

+0

отличная ссылка, спасибо –

ответ

8

Вы можете переопределить конструктор, но это немного сложнее, особенно если вы перекрывая конструктор по умолчанию. Вам необходимо назначить закрытие класса metaClass.constructor, и закрытие должно вернуть новый экземпляр. Сложная часть состоит в том, что если вы вызываете конструктор, который вы переопределили, вы попадете в рекурсивный цикл и создадите переполнение стека. Вам нужен другой способ получить экземпляр класса, например, другой конструктор.

Для тестирования иногда можно обойти это ограничение. Обычно достаточно сначала создать экземпляр объекта, а затем переопределить конструктор, чтобы вернуть существующий экземпляр. Пример:

class MyObject { 
    String something 
    MyObject() { something = "initialized" } 
} 

testInstance = new MyObject() 
testInstance.something = "overriden" 
MyObject.metaClass.constructor = { -> testInstance } 

aNewObject = new MyObject() 
assert aNewObject.is(testInstance) 
assert aNewObject.something == "overriden" 
+0

Я думаю, что я должен использовать 2 конструктора, чтобы получить то, что мне нужно. Благодарю. –

2

Можно добавить новые конструкторы или заменить старый. Если вам нужен оригинальный конструктор, вы можете использовать отражение для этого:

MyObject.metaClass.constructor = { -> // for the no-arg ctor 
    // use reflection to get the original constructor 
    def constructor = MyObject.class.getConstructor() 
    // create the new instance 
    def instance = constructor.newInstance() 
    // ... do some further stuff with the instance ... 
    println "Created ${instance}" 
    instance 
} 

Обратите внимание, что вы должны изменить это, если у вас есть параметры ваших конструкторов, например:

// Note that the closure contains the signature of the constructor 
MyObject.metaClass.constructor = { int year, String reason -> 
    def constructor = MyObject.class.getConstructor(Integer.TYPE, String.class) 
    def instance = constructor.newInstance(
    2014, "Boy, am I really answering a question three years old?") 
    // ... do some further stuff with the instance ... 
    println "Created ${instance}" 
    instance 
} 

PS: Обратите внимание, что при вы хотите добавить конструкторы, которые еще не существуют, вместо этого используйте оператор <<: MyObject.metaClass.constructor << { /* as above */ }.

1

Вы можете обойти ограничения в решении, предлагаемые путем хранения исходного конструктора с использованием стандартного отражения Java. Например, это то, что я инициализировать класс (базовые инъекции) в тесте Spock:

def setupSpec() { 
    MockPlexusContainer mockPlexusContainer = new MockPlexusContainer() 
    def oldConstructor = MY_CLASS.constructors[0] 

    MY_CLASS.metaClass.constructor = { -> 
     def mojo = oldConstructor.newInstance() 
     mockPlexusContainer.initializeContext(mojo) 
     return mojo 
    } 
} 

Это вызывается, только один раз, но eveytime кто-то вызывает конструктор я получаю другой экземпляр избегая значения очистки и обеспечение резьбы безопасность.

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