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

3

我有一个不可变的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来实现。

由于Entity类在prod代码中,我无法更改它,因此我尝试使用groovy.transform.builder.ExternalStrategy策略来使用构建器。

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

但是我无法将其用于不可变对象。

因此,我想知道实现不可变Java对象的Groovy构建器的最佳方法是什么?


由于几乎所有的Java文件也都是有效的Groovy文件,为什么不在Java代码中实现Builder呢?对于像上面这样简单的情况,这样做很容易。 - scottb
当然,如果找不到一个非常好的解决方案,这是我选择的方式。我想尝试在Groovy中做这件事只是为了学习目的。 - androberz
1
请注意,除非Entity类是final,否则它并不是真正的不可变类。 - jaco0646
2个回答

4

虽然你不是一个建造者,但只要你的类型有一个可以将列表项作为参数传递的构造函数,你就可以强制将 List 转换为你的类型:

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

如果您的类型有一个接受两个字符串的构造函数,则此方法可行。

由于您的类型没有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
快速的答案是:没有Groovy构建器转换可以为您的情况创建构建器。因此,您需要手动编写代码。有两个原因您不能使用构建器转换:
  1. 字段不是公共的,因此转换看不到它们,因此不会为它们创建构建器方法。
  2. 生成的build()方法期望正在构建的类包含一个无参构造函数和每个字段的setter。
为了说明我的意思,这里是一个满足要求的类生成的构建器代码片段:
@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 
    }

    ...

}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接