如何呼叫龙目岛的超级建筑师

我还有课

@Value
@NonFinal
public class A {
int x;
int y;
}

我还有一个 B 班

@Value
public class B extends A {
int z;
}

Lombok 抛出了一个错误,说它找不到 A ()构造函数,显式地调用它,我想让 lombok 做的是给类 b 添加注释,这样它就会生成以下代码:

public class B extends A {
int z;
public B( int x, int y, int z) {
super( x , y );
this.z = z;
}
}

我们在龙目岛有这样做的注释吗?

213736 次浏览

这在龙目岛是不可能的。虽然它是一个非常好的特性,但是它需要解析来查找超类的构造函数。只有在龙目岛被调用时,人们才知道这个超级阶层的名字。使用 import 语句和类路径查找实际的类并非易事。在编译期间,您不能仅仅使用反射来获取构造函数列表。

这并非完全不可能,但在 val@ExtensionMethod中使用分辨率的结果告诉我们,这是一个困难和容易出错的问题。

披露: 我是一个龙目岛开发商。

龙目岛问题 # 78 引用这一页的 https://www.donneo.de/2015/09/16/lomboks-builder-annotation-and-inheritance/有这样一个可爱的解释:

@AllArgsConstructor
public class Parent {
private String a;
}


public class Child extends Parent {
private String b;


@Builder
public Child(String a, String b){
super(a);
this.b = b;
}
}

因此,您可以像下面这样使用生成的构建器:

Child.builder().a("testA").b("testB").build();

正式文件解释了这一点,但没有明确指出您可以通过这种方式促进它。

我还发现这对 Spring Data JPA 非常有用。

龙目岛不支持使用任何 @Value注释类 final(如你所知,使用 @NonFinal)。

我发现的唯一变通方法是自己声明所有成员 final 并使用 @Data注释。这些子类需要由 @EqualsAndHashCode进行注释,并且需要一个显式的 all args 构造函数,因为龙目岛不知道如何使用超类的 all args 创建一个:

@Data
public class A {
private final int x;
private final int y;
}


@Data
@EqualsAndHashCode(callSuper = true)
public class B extends A {
private final int z;


public B(int x, int y, int z) {
super(x, y);
this.z = z;
}
}

特别是子类的构造函数使得有许多成员的超类的解决方案有点不整洁,抱歉。

对于具有许多成员的超类,我建议您使用

@Data
public class A {
@Delegate public class AInner{
private final int x;
private final int y;
}
}


@Data
@EqualsAndHashCode(callSuper = true)
public class B extends A {
private final int z;


public B(A.AInner a, int z) {
super(a);
this.z = z;
}
}

如果子类比父类有更多的成员,它可以做得不是很干净,但是方法很简单:

@Data
@RequiredArgsConstructor
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class User extends BaseEntity {
private @NonNull String fullName;
private @NonNull String email;
...


public User(Integer id, String fullName, String email, ....) {
this(fullName, email, ....);
this.id = id;
}
}


@Data
@AllArgsConstructor
abstract public class BaseEntity {
protected Integer id;


public boolean isNew() {
return id == null;
}
}

龙目岛版本1.18引入了@superBuilder 注释,我们可以用一种更简单的方法来解决我们的问题。

你可以参考 https://www.baeldung.com/lombok-builder-inheritance#lombok-builder-and-inheritance-3

所以在你们的孩子课上,你们需要这些注释:

@Data
@SuperBuilder
@NoArgsConstructor
@EqualsAndHashCode(callSuper = true)

在你的家长班:

@Data
@SuperBuilder
@NoArgsConstructor

如果没有正确的注释,可以使用 com.fasterxml.jackson.databind.ObjectMapper从父类初始化子类

public class A {
int x;
int y;
}


public class B extends A {
int z;
}


ObjectMapper MAPPER = new ObjectMapper(); //it's configurable
MAPPER.configure( DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false );
MAPPER.configure( SerializationFeature.FAIL_ON_EMPTY_BEANS, false );


//Then wherever you need to initialize child from parent:
A parent = new A(x, y);
B child = MAPPER.convertValue( parent, B.class);
child.setZ(z);

如果需要,您仍然可以在 A 和 B 上使用任何 lombok注释。