添加自定义构造函数而不会丢失默认的地图构造函数

时间:2014-10-14 13:28:35

标签: groovy constructor

默认情况下,每个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 个答案:

答案 0 :(得分:20)

如果您使用的是Groovy 2.5或更高版本,则可以应用@MapConstructor annotation

@groovy.transform.MapConstructor
class Foo {
    def a, b
    Foo(Integer x) {
        println 'my constructor was called'
    }
}

// this works
new Foo(1)

// the map constructor is present, too
def mappedFoo = new Foo(a: '1', b: '1')
assert mappedFoo.a == '1'
assert mappedFoo.b == '1'

如果您使用的是较早版本的Groovy,@InheritConstructors annotation可以替代@MapConstructor,但正如Arie指出的那样,如果您使用你的课程扩展了一些基类;如果基类缺少无参数构造函数,则无效。

答案 1 :(得分:9)

编译后,Groovy的地图构造函数被转换为object creation using an empty constructor plus a bunch of setters(以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"

答案 2 :(得分:4)

添加无法参与者并致电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