我有一个班级
@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;
}
}
我们在Lombok中有注释吗?
答案 0 :(得分:102)
这在龙目岛是不可能的。虽然这将是一个非常好的功能,但它需要解决方案才能找到超类的构造函数。在调用Lombok的那一刻,超类只能通过名称来识别。使用import语句和类路径来查找实际的类并非易事。在编译期间,您不能仅使用反射来获取构造函数列表。
这并非完全不可能,但使用val
和@ExtensionMethod
中的分辨率的结果告诉我们,它很难且容易出错。
披露:我是龙目岛的开发者。
答案 1 :(得分:16)
Lombok Issue #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();
official documentation解释了这一点,但没有明确指出您可以通过这种方式为其提供便利。
我还发现这适用于Spring Data JPA。
答案 2 :(得分:10)
Lombok的1.18版引入了@SuperBuilder批注。我们可以使用它以更简单的方式解决我们的问题。
您可以参考https://www.baeldung.com/lombok-builder-inheritance#lombok-builder-and-inheritance-3。
因此在您的子类中,您将需要以下注释:
@Data
@SuperBuilder
@NoArgsConstructor
@EqualsAndHashCode(callSuper = true)
在您的父班:
@Data
@SuperBuilder
@NoArgsConstructor
答案 3 :(得分:5)
Lombok不支持通过制作任何@Value
带注释的类final
来表示(正如您使用@NonFinal
所知)。
我找到的唯一解决方法是自己声明所有成员并最终使用@Data
注释。这些子类需要由@EqualsAndHashCode
注释,并且需要一个明确的所有args构造函数,因为Lombok不知道如何使用all class创建一个超类:
@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;
}
}
特别是子类的构造函数使得解决方案对于有很多成员的超类来说有点凌乱,抱歉。
答案 4 :(得分:2)
对于有很多成员的超类,我建议你使用@Delegate
@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;
}
}
答案 5 :(得分:1)
如果子类的成员多于父级,那么它可能不是很干净,但是很简单:
@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;
}
}
答案 6 :(得分:1)
作为一种选择,您可以使用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
注释。