FreeBuilder 是一个非常好用的基于 JAVA 注解处理器 APT (Annotation Processing Tool) 技术的数据实体类生成器,可以 通过简单的注解来生成 Builder 模式的实体类。AutoValue 是另一个非常好用的基于 APT 的类库,参见 Value Class Generated by Google AutoValue。二者的区别在于:

  1. AutoValue 根据开发者提供的一个 Builder 接口来实现具体的 Builder 类;FreeBuilder 则对给定的数据实体类生成符合固定规则的 Builder 类。前者可以控制生成的 Builder 类的方法列表,后者无法控制生成的 Builder 类的方法列表,但是可以通过继承生成的 Builder 类限制对外暴露的方法列表。
  2. AutoValue 需要数据实体类是一个抽象类;FreeBuilder 则同时支持抽象类和接口。

详细对比可以参考 FreeBuilder Alternatives

🔗Maven Settings

<dependency>
	<groupId>org.inferred</groupId>
	<artifactId>freebuilder</artifactId>
	<version>${freebuilder_version}</version>
	<scope>provided</scope>
</dependency>

freebuilder 中同时包含了定义数据实体类时需要的注解和注解处理器实现。

截至 2019-09-30 日, FreeBuilder 的最新版本是 2.4.1

🔗Abstract Class

一个基本的数据类如下:

@FreeBuilder
interface Task {
    Long id();
    String type();
    String description();

    static Builder builder() { return new Builder(); }

    class Builder extends Task_Builder { }
}

上述是所需要的全部代码。如果倾向于使用抽象类的话,可以换成:

@FreeBuilder
abstract class Task {
    abstract long getId();
    abstract String getType();
    abstract String getDescription();

    static Builder builder() { return new Builder(); }

    static class Builder extends Task_Builder { }
}

定义一个数据实体类,只需提供一个接口或抽象类,所需字段以接口方法/抽象方法声明即可,FreeBuilder 会通过 APT 生成一个名为 Task_Builder 的 Builder 类和两个分别名为 Task_Builder.ValueTask_Builder.Partial 的实现类。以上生成类的类名是由实体类名自动生成的。

每一个接口方法/抽象方法会被 FreeBuilder 标记为一个 property :如果方法名以 "get" 开头则对应的 property 名是方法名去掉 "get" 之后的部分,否则是整个方法名。

🔗Builder

FreeBuilder 会在 Task_Builder 中为 Task 中的每一个 property 生成一系列的方法。

🔗Regular Property

对于基本类型和普通类类型的 propertylong getId(),会生成:

方法说明
setId(long)Setter
getId()Getter
mapId(UnaryOperator)Mutator

示例如下:

@Generated("org.inferred.freebuilder.processor.Processor")
abstract class Task_Builder {
	// ...

	public Task.Builder setId(long id) {
		// ...
    }

    public Task.Builder mapId(UnaryOperator<Long> mapper) {
		// ...
    }

    public long getId() {
		// ...
    }

	// ...
}

🔗Property of Optional Type

对于 Optional (java.util.Optionalcom.google.common.base.Optional) 类型的 propertyOptional<String> getTitle(),会生成:

方法说明
setTitle(String)Setter with non-null value
setTitle(Optional)Setter with optional value
setNullableTitle(String)Setter with nullable value
getTitle()Getter
mapTitle(Spliterator)Mutator
clearTitle()Setter with Optional.empty()

示例如下:

public StudentDto.Builder setTitle(String title) {
	// ...
}

public StudentDto.Builder setTitle(Optional<? extends String> title) {
	// ...
}

public StudentDto.Builder setNullableTitle(String title) {
	// ...
}

public StudentDto.Builder mapTitle(UnaryOperator<String> mapper) {
	// ...
}

public StudentDto.Builder clearTitle() {
	// ...
}

public Optional<String> getTitle() {
	// ...
}

🔗Property of Collection Type

对于 List, Set, SortedSetMultiset 类型的 propertyList<String> getEmails() ,会生成:

方法说明
addEmails(String)Appends a single value
addEmails(String ...)Appends multi values
addAllEmails(Iterable)Appends all elements from a java.lang.Iterable
addAllEmails(Spliterator)Appends all elements from a java.util.Spliterator
addAllEmails(Stream)Appends all elements from a java.util.stream.Stream
mutateEmails(Consumer<List>)Mutates values by invoking a java.util.function.Consumer
clearEmails()Remove all elements
getEmails()Returns an unmodifiable view of all elements

示例如下:

public StudentDto.Builder addEmails(String element) {
	// ...
}

public StudentDto.Builder addEmails(String... elements) {
	// ...
}

public StudentDto.Builder addAllEmails(Spliterator<? extends String> elements) {
	// ...
}

public StudentDto.Builder addAllEmails(BaseStream<? extends String, ?> elements) {
	// ...
}

public StudentDto.Builder addAllEmails(Iterable<? extends String> elements) {
	// ...
}

public StudentDto.Builder mutateEmails(Consumer<? super List<String>> mutator) {
	// ...
}

public StudentDto.Builder clearEmails() {
	// ...
}

public List<String> getEmails() {
	// ...
}

🔗Property of Map Type

对于 Map 类型的 propertyMap<String, Integer> getScores(),会生成:

方法说明
putScores(String, Integer)Adds a key-value pair
putAllScores(Map<String, Integer>)Adds key-value pairs from an existed map
removeScores(String)Removes a pair with given key
mutateScores(Consumer<Map<String, Integer>>)Mutator
clearScores()Removes all pairs
getScores()Returns an unmodifiable view of all pairs

示例如下:

public StudentDto.Builder putScores(String key, int value) {
	// ...
}

public StudentDto.Builder putAllScores(Map<? extends String, ? extends Integer> map) {
	// ...
}

public StudentDto.Builder removeScores(String key) {
	// ...
}

public StudentDto.Builder mutateScores(Consumer<? super Map<String, Integer>> mutator) {
	// ...
}

public StudentDto.Builder clearScores() {
	// ...
}

public Map<String, Integer> getScores() {
	// ...
}

🔗Custom Propertys Generation

FreeBuilder 会自动生成数据实体类的 String toString() 方法和 boolean equals(Object);方法实现中会默认包含所有的 property

如果某个 property 不想被包含在 toString 方法中,可以对其添加 @NotInToString 注解。

如果某个 property 不想被包含在 equals 方法中,可以对其添加 @IgnoredByEquals 注解。


完整的示例代码可以参见 FreeBuilder Usecases


FreeBuilder 是这样的强大,以至于我正在使用它逐步替换 AutoValue

以上。