Добавление настраиваемого конструктора без потери конструктора карты по умолчанию

По умолчанию каждый класс Groovy имеет конструктор Map, например

class Foo {
 def a
 def b
}
// this works
new Foo(a: '1', b: '2')

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

class Foo {
 Foo(Integer x) {
 println 'my constructor was called' 
 }
 def a
 def b
}
// this works
new Foo(1)
// now this doesn't work, I get the error: groovy.lang.GroovyRuntimeException: 
// failed to invoke constructor
new Foo(a: '1', b: '2')

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

public Foo(Map map) { 
 map?.each { k, v -> this[k] = v } 
}

Хотя конструктор выше не идентичен конструктору карты по умолчанию, потому что ключ на карте, который не имеет соответствующего свойства в классе, вызовет исключение.

3 ответа

Вы можете использовать аннотацию @InheritConstructors.

@groovy.transform.InheritConstructors
class Foo {
 def a, b
 Foo(Integer x) {
 println 'my constructor was called'
 }
}
// this works
new Foo(1)
def mappedFoo = new Foo(a: '1', b: '1')
assert mappedFoo.a == '1'
assert mappedFoo.b == '1'


После компиляции конструктор карты Groovy преобразуется в создание объекта с использованием пустого конструктора плюс набор настроек (в стиле javabean). Наличие пустого конструктора решает проблему:

class Foo {
 Foo(Integer x) {
 println 'my constructor was called' 
 }
 Foo() {}
 def a
 def b
}
new Foo(1)
foo = new Foo(a: '1', b: '2')
assert foo.a == "1"


Добавьте no-arg ctor и вызовите super, например,

class Foo {
 Foo(Integer x) {
 println 'my constructor was called' 
 }
 Foo() { super() } // Or just Foo() {}
 def a
 def b
}
f = new Foo(a: '1', b: '2')
println f.a
=> 1

licensed under cc by-sa 3.0 with attribution.