繁体   English   中英

如何在 Lombok 中调用超级构造函数

[英]how to Call super constructor in Lombok

我有一堂课

@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 时才知道超类的名称。 使用导入语句和类路径来查找实际类并非易事。 在编译期间,您不能仅使用反射来获取构造函数列表。

这并非完全不可能,但在val@ExtensionMethod使用分辨率的结果告诉我们,这很难且容易出错。

披露:我是龙目岛的开发人员。

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();

官方文档对此进行了解释,但并没有明确指出您可以通过这种方式为其提供便利。

我还发现这与 Spring Data JPA 配合得很好。

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

Lombok 不支持通过将任何@Value注释类@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;
   }
}

作为一个选项,您可以使用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注释。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM