Java 如何在Lombok中调用超级构造函数
我有一节课Java 如何在Lombok中调用超级构造函数,java,lombok,Java,Lombok,我有一节课 @Value @NonFinal public class A { int x; int y; } 我还有一个B班 @Value public class B extends A { int z; } lombok抛出了一个错误,说它找不到()构造函数,显式地调用它。我希望lombok做的是给类b添加注释,以便它生成以下代码: public class B extends A { int z; public B( int x, int y,
@Value
@NonFinal
public class A {
int x;
int y;
}
我还有一个B班
@Value
public class B extends A {
int z;
}
lombok抛出了一个错误,说它找不到()构造函数,显式地调用它。我希望lombok做的是给类b添加注释,以便它生成以下代码:
public class B extends A {
int z;
public B( int x, int y, int z) {
super( x , y );
this.z = z;
}
}
我们在Lombok中有这样做的注释吗?这在Lombok中是不可能的。虽然这将是一个非常好的特性,但它需要解析才能找到超类的构造函数。超级类只有在Lombok被调用时才知道名称。使用import语句和classpath查找实际的类并不是一件小事。在编译过程中,不能仅仅使用反射来获取构造函数列表 这并非完全不可能,但使用
val
和@ExtensionMethod
中的分辨率得到的结果告诉我们,这很难而且容易出错
披露:我是一名Lombok开发者。引用此页面,并给出以下可爱的解释:
因此,您可以使用生成的生成器,如下所示:
Child.builder().a("testA").b("testB").build();
说明了这一点,但没有明确指出您可以通过这种方式来促进它
我还发现这对Spring数据JPA也很有效。Lombok不支持通过生成任何
@Value
注释类final
(正如您使用@NonFinal
所知道的那样)
我找到的唯一解决办法是自己声明所有成员为final,并使用@Data
注释。这些子类需要由@EqualsAndHashCode
注释,并且需要一个显式的all args构造函数,因为Lombok不知道如何使用超类中的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;
}
}
特别是子类的构造函数使得解决方案对于具有多个成员的超类来说有点混乱,对不起。对于具有多个成员的超类,我建议您使用@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;
}
}
若子类的成员比父类多,那个么这可能不是很干净,但方法很简单:
@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;
}
}
Lombok的1.18版引入了@SuperBuilder注释。我们可以用一种更简单的方法来解决我们的问题 你可以参考 因此,在您的子类中,您将需要以下注释:
@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
注释。@roel spilker我们理解其背后的复杂性。但是Lombok能为构造函数注释提供一个inConstructor
方法吗?在这个方法中,我们可以指定Lombok应该在生成的构造函数中注入super
的哪个构造函数?afterConstructor也可以做一些自动操作initialization@Manu/@Pawel:参见lombok增强请求:(当前打开)由于@Builder处于正式版本,请参见:仍然不可能?您能否提供一个与Spring数据JPA一起使用的示例?这根本无法回答问题。相反,它是手工完成工作的,而问题是如何生成它。同时,拖动@Builder会让整个事情变得更加混乱,这与问题无关。实际上,这对于那些只想创建继承结构然后使用Builder的人来说非常有用。这就是我99%使用龙目山的原因。有时候,我们只是需要手工制作一些东西来让它按照我们的愿望工作;只需编写self+父参数构造函数。不需要使用builderIt,它可以在STS&eclipse中工作,但当您生成应用程序的JAR文件时,很可能会失败。我尝试了SuperBuilder和继承生成器。两人都失败了。小心!!你能再解释一下为什么“子类需要用@EqualsAndHashCode
注释”吗?@Data
不包括此注释吗?Thx:)@GerardB@Data
也创建equals()和hashCode(),但不关心任何继承。为了确保使用超类equals()和hashCode(),您需要使用callsuper显式生成这是一种有趣的方法,就像它一样@Delegate
是@Target({ElementType.FIELD,ElementType.METHOD})
AInner
应该是A
中的字段。这不适用于OP的@Value
,因为如果没有无参数构造函数,Jackson将失败。即使它确实有效,序列化为json并对每个新的进行反序列化也是非常愚蠢的。对于SuperBuilder,AllArgsConstructor是否同时包含来自父级和子级的参数?谢谢
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);