Go...
Go...
@groovy.transform.builder.Builder
@Builder AST 转换用于帮助编写可以使用*流式* API 调用创建的类。该转换支持多种构建策略以涵盖各种情况,并且有许多配置选项可以自定义构建过程。如果您是 AST 黑客,您还可以定义自己的策略类。下表列出了 Groovy 中捆绑的可用策略以及每种策略支持的配置选项。
策略
描述
builderClassName
builderMethodName
buildMethodName
prefix
includes/excludes
includeSuperProperties
allNames
SimpleStrategy
链式setter
不适用
不适用
不适用
是,默认“set”
是
不适用
是,默认 false
ExternalStrategy
显式构建器类,正在构建的类不受影响
不适用
不适用
是,默认“build”
是,默认“”
是
是,默认 false
是,默认 false
DefaultStrategy
创建一个嵌套辅助类
是,默认
是,默认“builder”
是,默认“build”
是,默认“”
是
是,默认 false
是,默认 false
InitializerStrategy
创建一个提供类型安全流畅创建的嵌套辅助类
是,默认
是,默认“createInitializer”
是,默认“create”,但通常仅在内部使用
是,默认“”
是
是,默认 false
是,默认 false
SimpleStrategy
要使用 SimpleStrategy,请使用 @Builder 注解您的 Groovy 类,并指定策略,如本例所示:
import groovy.transform.builder.*
@Builder(builderStrategy=SimpleStrategy)
class Person {
String first
String last
Integer born
}
然后,只需像这样以链式方式调用 setter:
def p1 = new Person().setFirst('Johnny').setLast('Depp').setBorn(1963)
assert "$p1.first $p1.last" == 'Johnny Depp'
对于每个属性,将创建一个生成的 setter,如下所示:
public Person setFirst(java.lang.String first) {
this.first = first
return this
}
您可以指定一个前缀,如本例所示:
import groovy.transform.builder.*
@Builder(builderStrategy=SimpleStrategy, prefix="")
class Person {
String first
String last
Integer born
}
调用链式 setter 将如下所示:
def p = new Person().first('Johnny').last('Depp').born(1963)
assert "$p.first $p.last" == 'Johnny Depp'
您可以将 SimpleStrategy 与 @TupleConstructor 结合使用。如果您的 @Builder 注解没有显式的 includes 或 excludes 注解属性,但您的 @TupleConstructor 注解有,那么 @TupleConstructor 中的属性将被 @Builder 重用。这同样适用于任何组合 @TupleConstructor 的注解别名,例如 @Canonical。
如果您希望在构造过程中调用某个 setter,可以使用 useSetters 注解属性。详情请参阅 JavaDoc。
此策略不支持注解属性 builderClassName、buildMethodName、builderMethodName、forClass 和 includeSuperProperties。
Groovy 已经内置了构建机制。如果内置机制满足您的需求,请不要急于使用 @Builder。以下是一些示例:
def p2 = new Person(first: 'Keira', last: 'Knightley', born: 1985)
def p3 = new Person().with {
first = 'Geoffrey'
last = 'Rush'
born = 1951
}
ExternalStrategy
要使用 ExternalStrategy,请使用 @Builder 注解创建和注解 Groovy 构建器类,使用 forClass 指定构建器适用的类,并指示使用 ExternalStrategy。假设您有以下想要为其构建器的类:
class Person {
String first
String last
int born
}
您显式创建并使用构建器类,如下所示:
import groovy.transform.builder.*
@Builder(builderStrategy=ExternalStrategy, forClass=Person)
class PersonBuilder { }
def p = new PersonBuilder().first('Johnny').last('Depp').born(1963).build()
assert "$p.first $p.last" == 'Johnny Depp'
请注意,您提供的(通常为空的)构建器类将填充适当的 setter 和构建方法。生成的构建方法将类似于:
public Person build() {
Person _thePerson = new Person()
_thePerson.first = first
_thePerson.last = last
_thePerson.born = born
return _thePerson
}
您正在为其创建构建器的类可以是遵循正常 JavaBean 约定的任何 Java 或 Groovy 类,例如,无参数构造函数和属性的 setter。这是一个使用 Java 类的示例:
import groovy.transform.builder.*
@Builder(builderStrategy=ExternalStrategy, forClass=javax.swing.DefaultButtonModel)
class ButtonModelBuilder {}
def model = new ButtonModelBuilder().enabled(true).pressed(true).armed(true).rollover(true).selected(true).build()
assert model.isArmed()
assert model.isPressed()
assert model.isEnabled()
assert model.isSelected()
assert model.isRollover()
生成的构建器可以使用 prefix、includes、excludes 和 buildMethodName 注解属性进行自定义。这是一个说明各种自定义的示例:
import groovy.transform.builder.*
import groovy.transform.Canonical
@Canonical
class Person {
String first
String last
int born
}
@Builder(builderStrategy=ExternalStrategy, forClass=Person, includes=['first', 'last'], buildMethodName='create', prefix='with')
class PersonBuilder { }
def p = new PersonBuilder().withFirst('Johnny').withLast('Depp').create()
assert "$p.first $p.last" == 'Johnny Depp'
此策略不适用于 @Builder 的 builderMethodName 和 builderClassName 注解属性。
您可以将 ExternalStrategy 与 @TupleConstructor 结合使用。如果您的 @Builder 注解没有显式的 includes 或 excludes 注解属性,但您正在为其创建构建器的类的 @TupleConstructor 注解有,那么 @TupleConstructor 中的属性将被 @Builder 重用。这同样适用于任何组合 @TupleConstructor 的注解别名,例如 @Canonical。
DefaultStrategy
要使用 DefaultStrategy,请使用 @Builder 注解您的 Groovy 类,如本例所示:
import groovy.transform.builder.Builder
@Builder
class Person {
String firstName
String lastName
int age
}
def person = Person.builder().firstName("Robert").lastName("Lewandowski").age(21).build()
assert person.firstName == "Robert"
assert person.lastName == "Lewandowski"
assert person.age == 21
如果您愿意,可以使用 builderClassName、buildMethodName、builderMethodName、prefix、includes 和 excludes 注解属性自定义构建过程的各个方面,其中一些在本例中有所使用:
import groovy.transform.builder.Builder
@Builder(buildMethodName='make', builderMethodName='maker', prefix='with', excludes='age')
class Person {
String firstName
String lastName
int age
}
def p = Person.maker().withFirstName("Robert").withLastName("Lewandowski").make()
assert "$p.firstName $p.lastName" == "Robert Lewandowski"
此策略还支持注释静态方法和构造函数。在这种情况下,静态方法或构造函数参数将成为用于构建目的的属性,在静态方法的情况下,方法的返回类型将成为正在构建的目标类。如果一个类中使用了多个 @Builder 注解(在类、方法或构造函数位置),则由您来确保生成的辅助类和工厂方法具有唯一的名称(即不能有多个使用默认名称值)。有关方法和构造函数使用示例,但使用 DefaultStrategy 策略,请参阅该策略的文档。
import groovy.transform.builder.*
import groovy.transform.*
@ToString
@Builder
class Person {
String first, last
int born
Person(){}
@Builder(builderClassName='MovieBuilder', builderMethodName='byRoleBuilder')
Person(String roleName) {
if (roleName == 'Jack Sparrow') {
this.first = 'Johnny'; this.last = 'Depp'; this.born = 1963
}
}
@Builder(builderClassName='NameBuilder', builderMethodName='nameBuilder', prefix='having', buildMethodName='fullName')
static String join(String first, String last) {
first + ' ' + last
}
@Builder(builderClassName='SplitBuilder', builderMethodName='splitBuilder')
static Person split(String name, int year) {
def parts = name.split(' ')
new Person(first: parts[0], last: parts[1], born: year)
}
}
assert Person.splitBuilder().name("Johnny Depp").year(1963).build().toString() == 'Person(Johnny, Depp, 1963)'
assert Person.byRoleBuilder().roleName("Jack Sparrow").build().toString() == 'Person(Johnny, Depp, 1963)'
assert Person.nameBuilder().havingFirst('Johnny').havingLast('Depp').fullName() == 'Johnny Depp'
assert Person.builder().first("Johnny").last('Depp').born(1963).build().toString() == 'Person(Johnny, Depp, 1963)'
此策略不支持 forClass 注解属性。
InitializerStrategy
要使用 InitializerStrategy,请使用 @Builder 注解您的 Groovy 类,并指定策略,如本例所示:
import groovy.transform.builder.*
import groovy.transform.*
@ToString
@Builder(builderStrategy=InitializerStrategy)
class Person {
String firstName
String lastName
int age
}
您的类将被锁定为只有一个公共构造函数,该构造函数接受一个“完全设置”的初始化器。它还将有一个工厂方法来创建初始化器。它们的使用方式如下:
@CompileStatic
def firstLastAge() {
assert new Person(Person.createInitializer().firstName("John").lastName("Smith").age(21)).toString() == 'Person(John, Smith, 21)'
}
firstLastAge()
任何涉及设置所有属性(尽管顺序不重要)的初始化器使用尝试都将导致编译错误。如果您不需要这种严格性级别,则无需使用 @CompileStatic。
您可以将 InitializerStrategy 与 @Canonical 和 @Immutable 结合使用。如果您的 @Builder 注解没有显式的 includes 或 excludes 注解属性,但您的 @Canonical 注解有,则 @Canonical 中的属性将重新用于 @Builder。这里有一个使用 @Builder 与 @Immutable 的示例:
import groovy.transform.builder.*
import groovy.transform.*
import static groovy.transform.options.Visibility.PRIVATE
@Builder(builderStrategy=InitializerStrategy)
@Immutable
@VisibilityOptions(PRIVATE)
class Person {
String first
String last
int born
}
def publicCons = Person.constructors
assert publicCons.size() == 1
@CompileStatic
def createFirstLastBorn() {
def p = new Person(Person.createInitializer().first('Johnny').last('Depp').born(1963))
assert "$p.first $p.last $p.born" == 'Johnny Depp 1963'
}
createFirstLastBorn()
如果您希望在构造过程中调用某个 setter,可以使用 useSetters 注解属性。详情请参阅 JavaDoc。
此策略还支持注释静态方法和构造函数。在这种情况下,静态方法或构造函数参数将成为用于构建目的的属性,在静态方法的情况下,方法的返回类型将成为正在构建的目标类。如果一个类中使用了多个 @Builder 注解(在类、方法或构造函数位置),则由您来确保生成的辅助类和工厂方法具有唯一的名称(即不能有多个使用默认名称值)。有关方法和构造函数使用示例,但使用 DefaultStrategy 策略,请参阅该策略的文档。
此策略不支持 forClass 注解属性。