为java不可变对象实现Groovy构建器的最佳方法

时间:2016-03-29 12:05:21

标签: java groovy builder

我有一个不可变的Java对象,如下所示:

public class Entity {
    private String field1;
    private String field2;

    public Entity(String field1, String field2) {
        this.field1 = field1;
        this.field2 = field2;
    }

    public String getField1() {...}
    public String getField2() {...}
}

我想在我的测试代码中添加一个用Groovy编写的类的构建器。我已尝试使用@groovy.transform.builder.Builder。 在这里,我无法在prod代码中更改Entity类,因此我尝试使用带有groovy.transform.builder.ExternalStrategy策略的构建器。

@Builder(builderStrategy = ExternalStrategy, forClass = Entity)
class EntityBuilder {
}

但我不能将它用于不可变对象。

所以我想知道为不可变java对象实现groovy构建器的最佳方法是什么?

2 个答案:

答案 0 :(得分:2)

不是真正的构建器,但只要它有一个可以将List项作为参数的构造函数,就可以强制List为您的类型:

def entity = [ 'hi', 'hej' ] as Entity

如果你的类型有一个带2个字符串的构造函数,那么这是有效的。

由于您的类型没有setter,Groovy无法猜测哪个参数具有哪个名称,因此无法自动生成构建器。

但是,您可以手动编写一些代码来实现一些不错的代码。

例如:

@Builder
class GroovyEntity {
    String field1
    String field2

    def asType( Class type ) {
        if ( type == Entity ) {
            return new Entity( field1, field2 )
        }
        super.asType( type )
    }
}

您可以这样使用:

Entity entity = GroovyEntity.builder()
            .field1( 'hi' )
            .field2( 'hej' )
            .build() as Entity

答案 1 :(得分:1)

快速回答是没有Groovy构建器转换可以为您的情况创建构建器。所以你必须手动编码。您无法使用构建器转换有两个原因:

  1. 字段不公开,因此转换看不到它们,因此不会为它们创建构建方法。
  2. 生成的build()方法要求构建的类包含无参构造函数和每个字段的setter。
  3. 为了说明我的意思,这里是为满足要求的类生成的构建器代码片段:

    @groovy.transform.builder.Builder(forClass = Person, builderStrategy = groovy.transform.builder.ExternalStrategy)
    public class PersonBuilder implements groovy.lang.GroovyObject extends java.lang.Object { 
    
        private java.lang.String firstName 
        private java.lang.String lastName 
        ...
    
        public PersonBuilder firstName(java.lang.String firstName) {
            this .firstName = firstName 
            return this 
        }
    
        public PersonBuilder lastName(java.lang.String lastName) {
            this .lastName = lastName 
            return this 
        }
    
        public Person build() {
            Person _thePerson = new Person()
            _thePerson .firstName = firstName 
            _thePerson .lastName = lastName 
            return _thePerson 
        }
    
        ...
    
    }