2014-09-29 3 views
5

Я новичок в groovy и только начал изучать его возможности метапрограммирования. Я застрял в добавлении недостающих свойств в вызов конструктора компонентов.Добавить недостающее свойство в вызове конструктора @Canonical bean?

В классе, который будет использоваться с FactoryBuilderSupport, я хочу динамически добавлять те свойства, которые еще не определены и предоставлены во время вызова конструктора. Вот урезанная версия:

@Canonical 
class MyClass { 
    def startDate 
    def additionalProperties = [:] 

    def void propertyMissing(String name, value) { 
     additionalProperties[name] = value 
    } 
} 

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

def thing = new MyClass(startDate: DateTime.now(), duration: 1234) 

Продолжительность свойство не существует , и я ожидал, что это будет обработано через propertyMissing. Насколько я понимаю groovy, вызов tuple-constructor приводит к вызову конструктора без аргумента, за которым следуют вызовы созданных groovy сеттеров. Так почему я получаю MissingPropertyException?

Как я новичок в groovy, я, вероятно, пропустил некоторые основные правила AST или MOP. Я был бы очень признателен за вашу помощь.

+0

в качестве обходного пути, вы можете использовать 'Expando', который обрабатывает это т е р: '@groovy.transform.InheritConstructors @ groovy.transform.ToString @ groovy.transform.EqualsAndHashCode класс MyClass расширяет EXPANDO {Защиты startDate} ' – cfrick

ответ

1

Если вы используете @Canonical и вы определяете первый объект класса с def, как вы делаете с startDate аннотацию генерируют следующие конструктор:

@Canonical 
class MyClass { 
    def startDate 
    def additionalProperties = [:] 

    def void propertyMissing(String name, value) { 
      additionalProperties[name] = value 
    } 
} 

// use reflection to see the constructors 
MyClass.class.getConstructors() 

сгенерированных конструкторы:

public MyClass() 
public MyClass(java.lang.Object) 
public MyClass(java.util.LinkedHashMap) 
public MyClass(java.lang.Object,java.lang.Object) 

В @Canonicaldocumentation вы можете увидеть следующее ограничение:

нормальных соглашения карты стиль именования

Groovy не будут доступны, если первое свойство имеет тип LinkedHashMap или если есть одна карта, AbstractMap или HashMap недвижимости

Благодаря public MyClass(java.util.LinkedHashMap) генерируются вы не можете использовать tuple-constructor и вы получите MissingPropertyException.

Удивительно, если вы определяете first объекта (обратите внимание, что я говорю о first) с type вместо использования def, @Canonical аннотаций не добавляет public MyClass(java.util.LinkedHashMap) и затем ваши tuple-constructor вызова работы, см следующий код:

@Canonical 
class MyClass { 
    java.util.Date startDate 
    def additionalProperties = [:] 

    def void propertyMissing(String name, value) { 
      additionalProperties[name] = value 
    } 
} 
// get the constructors 
MyClass.class.getConstructors() 
// now your code works 
def thing = new MyClass(startDate: new java.util.Date(), duration: 1234) 

Теперь созданные конструкторы:

public MyClass() 
public MyClass(java.util.Date) 
public MyClass(java.util.Date,java.lang.Object) 

Так, так как там не public MyClass(java.util.LinkedHashMap) ограничение не распространяется, и вы работаете tuple-constructor.

Кроме того, я хочу сказать, что, поскольку это решение работает, я не могу спорить, почему ... Я читал документацию @Canonical снова и снова, и я не вижу той части, где описано это поведение, я знаю, почему работает таким образом, также я делаю некоторые попытки, и я немного запутан, только когда first элемент def создан public MyClass(java.util.LinkedHashMap) i.е:

@Canonical 
class MyClass { 
    def a 
    int c 
} 
// get the constructors 
MyClass.class.getConstructors() 

Первый объект определен как def ...

public MyClass() 
public MyClass(java.lang.Object) 
public MyClass(java.util.LinkedHashMap) // first def... 
public MyClass(java.lang.Object,int) 

Теперь, если изменить порядок:

@Canonical 
class MyClass { 
    int c 
    def a 
} 
// get the constructors 
MyClass.class.getConstructors() 

Теперь первый не является def и public MyClass(java.util.LinkedHashMap) не генерируется:

public MyClass() 
public MyClass(int) 
public MyClass(int,java.lang.Object) 

Надеется, что это помогает,