Lombok @builder в классе, который расширяет другой класс
У меня есть два класса Child
extends Parent
. Мне нужно поставить аннотацию @Builder на классы, чтобы мне не нужно было создавать свой конструктор.
package jerry;// Internal compiler error: java.lang.NullPointerException
import lombok.AllArgsConstructor;
import lombok.Builder;
@AllArgsConstructor([email protected]__(@Builder))
public class Child extends Parent {
//Multiple markers at this line
// - Implicit super constructor Parent() is undefined. Must explicitly invoke another constructor
// - overrides java.lang.Object.toString
private String a;
private int b;
private boolean c;
}
@Builder
public class Parent {
private double d;
private float e;
}
Мне нужно создать дочерний экземпляр таким образом, чтобы
Child child = Child.builder().a("aVal").b(1000).c(true).d(10.1).e(20.0F).build();
Но до сих пор я получаю ошибки, упомянутые в этом комментарии кодов. Может ли кто-нибудь указать мне в правильном направлении, как достичь этого с помощью ломбока или любой другой подобной библиотеки?
Суб-вопрос
Почему компиляция @AllArgsConstructor([email protected]__(@Autowired))
, но @AllArgsConstructor([email protected]__(@Builder))
не работает?
Ответы
Ответ 1
Смотрите https://blog.codecentric.de/en/2016/05/reducing-boilerplate-code-project-lombok/ (часть @Builder и наследование)
Скорректировано для ваших классов
@AllArgsConstructor
public class Parent {
private double d;
private float e;
}
public class Child extends Parent {
private String a;
private int b;
private boolean c;
@Builder
public Child(String a, int b, boolean c, double d, float e) {
super(d, e);
this.a = a;
this.b = b;
this.c = c;
}
}
С помощью этой настройки
Child child = Child.builder().a("aVal").b(1000).c(true).d(10.1).e(20.0F).build();
работает правильно
Ответ 2
Начиная с версии 1.18.2, ломбок включает в себя новый эксперимент @SuperBuilder
. Он поддерживает поля из суперклассов (также абстрактных). С его помощью решение так просто:
@SuperBuilder
public class Child extends Parent {
private String a;
private int b;
private boolean c;
}
@SuperBuilder
public class Parent {
private double d;
private float e;
}
Child instance = Child.builder().b(7).e(6.3).build();
Обновление 2019-10-09: если вы используете IntelliJ, для использования @SuperBuilder
вам нужна как минимум версия 0.27 плагина IntelliJ Lombok.
PS: @AllArgsConstructor([email protected]__(@Builder))
не работает, потому что @Builder
является аннотацией обработки аннотации, которую lombok преобразует в код во время компиляции. Создание и последующее преобразование новой аннотации lombok потребует нескольких итераций обработки аннотации, и lombok не поддерживает это. @Autowired
, напротив, является обычной аннотацией Java, доступной во время выполнения.
Ответ 3
У меня есть аналогичный, но немного другой вариант использования. В моем случае у меня есть цепочка абстрактных суперклассов, которые строят и выполняют запросы. Различные запросы имеют общие параметры, но не каждый запрос поддерживает все параметры. Строители для конкретных запросов должны предоставлять только методы для установки поддерживаемых параметров для данного запроса.
Я начал работу с реализацией конструктора на основе конструктора, но это привело к слишком большому шаблону кода, особенно если у вас есть много полей для настройки. Теперь я придумал следующие решения, которые выглядят намного чище для меня.
В основном конкретные подклассы определяют фактические поля, которые Builder должен поддерживать, а аннотация Getter приводит к переопределению соответствующих методов суперкласса. Геттеры в абстрактных суперклассах могут даже быть определены как абстрактные, чтобы требовать конкретных реализаций для определения этих полей.
public abstract class AbstractSuperClass1 {
protected String getParamA() { return "defaultValueA"; }
public final void doSomething() {
System.out.println(getParamA());
doSomeThingElse();
}
protected abstract void doSomeThingElse();
}
public abstract class AbstractSuperClass2 extends AbstractSuperClass1 {
protected String getParamB() { return "defaultValueB"; }
protected void doSomeThingElse() {
System.out.println(getParamB());
}
}
import lombok.AccessLevel;
import lombok.Builder;
import lombok.Getter;
@Getter(AccessLevel.PROTECTED) @Builder
public class ConcreteClass1 extends AbstractSuperClass2 {
private final String paramA;
// Not supported by this implementation: private final String paramB;
public static void main(String[] args) {
ConcreteClass1.builder()
.paramA("NonDefaultValueA")
.build().doSomething();
}
}
import lombok.AccessLevel;
import lombok.Builder;
import lombok.Getter;
@Getter(AccessLevel.PROTECTED) @Builder
public class ConcreteClass2 extends AbstractSuperClass2 {
private final String paramA;
private final String paramB;
public static void main(String[] args) {
ConcreteClass2.builder()
.paramA("NonDefaultValueA").paramB("NonDefaultValueB")
.build().doSomething();
}
}