Добавить отсутствующее свойство в вызове конструктора bean-компонента @Canonical?
Я новичок в Groovy и только начал изучать его возможности метапрограммирования. Я застрял с добавлением недостающих свойств при вызове конструктора бина.
В классе, который будет использоваться с 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 приводит к вызову конструктора без аргументов, за которым следуют вызовы сгенерированных groovy сеттеров. Так почему я получаю MissingPropertyException
?
Поскольку я новичок в Groovy, я, вероятно, скучаю по некоторым основным правилам AST или MOP. Я был бы очень признателен за вашу помощь.
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)
в @Canonical
В документации вы можете увидеть следующие ограничения:
Обычные правила именования в стиле карты Groovy будут недоступны, если первое свойство имеет тип LinkedHashMap или если имеется одно свойство Map, 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)
создан то есть:
@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)
Надеюсь это поможет,