Java 存在哪些工具或库,仅采用访问器方法定义的
interface
并自动生成不可变的对象类以及用于增量构建新实例或通过创建新实例来更改现有实例的“构建器”类?
输入示例:
public interface Car {
String getModelName();
int getWheelCount();
}
输出示例:
import javax.annotation.concurrent.Immutable;
import javax.annotation.concurrent.NotThreadSafe;
@Immutable
public final class ImmutableCar implements Car {
@NotThreadSafe
public static final class Builder implements Car {
private String modelName;
private int wheelCount;
public Builder() {
}
public Builder(final Car car) {
modelName = car.getModelName();
wheelCount = car.getWheelCount();
}
public ImmutableCar build() {
return new ImmutableCar(wheelCount, modelName);
}
@Override
public String getModelName() {
return modelName;
}
@Override
public int getWheelCount() {
return wheelCount;
}
public void setModelName(final String modelName) {
this.modelName = modelName;
}
public void setWheelCount(final int wheelCount) {
this.wheelCount = wheelCount;
}
}
private final String modelName;
private final int wheelCount;
public ImmutableCar(final int wheelCount, final String modelName) {
this.wheelCount = wheelCount;
this.modelName = modelName;
}
@Override
public String getModelName() {
return modelName;
}
@Override
public int getWheelCount() {
return wheelCount;
}
}
Immutables (http://immutables.github.io) 注释处理器完全满足您的需求。它功能齐全且非常可定制(您知道所有这些
set
vs with
vs 无前缀战争, - 使用您喜欢的任何内容)。它可以使用接口、抽象类、注释的构建器生成不可变的实现。此外,它还可以生成构建器来调用静态工厂方法或 POJO 构造函数以及许多其他东西。
@Value.Immutable
public interface ValueObject {
String name();
List<Integer> counts();
Optional<String> description();
}
// Compile using annotation processor and use it like this
ValueObject valueObject =
ImmutableValueObject.builder()
.name("My value")
.addCounts(1)
.addCounts(2)
.build();
Lombok允许这样的代码:
@lombok.Data
@lombok.Builder
public class ImmutableCar implements Car {
private final @lombok.NonNull String modelName;
private final @lombok.NonNull int wheelCount;
}
lombok 注释在编译时 (JSR-269) 进行处理以生成完整的类。还可以通过 Maven 插件通过“delomboking”查看生成的代码。
Google
有一个名为 AutoValue 的工具可以执行此操作,但基于抽象基类而不是接口。
import com.google.auto.value.AutoValue;
class Example {
@AutoValue
abstract static class Animal {
static Builder builder() {
return new AutoValue_Example_Animal.Builder();
}
abstract String name();
abstract int numberOfLegs();
@AutoValue.Builder
abstract static class Builder {
abstract Builder name(String s);
abstract Builder numberOfLegs(int n);
abstract Animal build();
}
}
}
另一个类似的工具是Immutables;这可能更接近问题,因为它使用接口并生成不可变的实现和构建器。
查看 Eclipse Model2Text 项目 及其子项目,特别是 Acceleo 和 Xpand。它们通常用于为 EMF 模型生成基于 EMF 的 Java 代码,但它们也可以用于生成简单的 POJO。
但是,此功能并不是现成的:您必须为其创建自己的代码生成器和模板。请参阅 Accelelo 教程 .
编辑:
还有一个想法 - 一个如此简单的想法,我花了一天时间才意识到它
您可以使用Velocity、Freemarker或类似的模板库(通常用于html生成)。但您仍然需要在某个地方创建模型,例如在 .txt 或 .xml 文件中。这是 Velocity 代码生成教程。
我刚刚创建了一个 Eclipse 插件 https://github.com/karajdaar/templator。
它基于 Freemarker 模板生成代码。 Freemarker 模板的上下文是一个 ICompilationUnit,它允许完全访问命名类及其信息。我们使用它为 NoSQL 数据库、球衣客户端、测试等生成 DAO。
我认为它可以轻松完成这里需要的事情。
这是我今天如何使用提出问题时不可用的功能来实现的。
在 Java 14+ 中,有
records
,一种创建不可变类的内置方法,并且它与 lomboks 构建器兼容:
@Builder
public record Person(String name, String address) {}
这将创建一个不可变的
Person
类,其中包含所有常见方法(相等、构造函数、getter),其行为与 Java 类的预期相同。 Lombok 将生成构建器。
有关记录的详细信息可以在 Baeldung、the JEP 或oracle 中找到,但由于它们旨在实现您所期望的功能,因此您可能不必深入了解。
限制:记录不支持继承。但您可以定义自定义方法并实现接口。