it-swarm.com.ru

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)) нет?

18
zur

Смотрите в https://blog.codecentric.de/ru/2016/05/reduc-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();

работает правильно

23
hammerfest

Последний выпуск lombok 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();

PS: @AllArgsConstructor([email protected]__(@Builder)) не работает, потому что @Builder - это аннотация обработки аннотаций, которую lombok преобразует в код во время компиляции. Генерация и последующая трансляция новой аннотации lombok потребует нескольких итераций обработки аннотации, и lombok не поддерживает это. Напротив, @Autowired - это обычная аннотация Java, доступная во время выполнения.

17
Jan Rieke

У меня похожий, но немного другой вариант использования. В моем случае у меня есть цепочка абстрактных суперклассов, которые создают и выполняют запросы. Различные запросы имеют общие параметры, но не каждый запрос поддерживает все параметры. Разработчики для конкретных запросов должны предоставлять только методы для установки поддерживаемых параметров для данного запроса. 

Я начал с реализаций на основе конструктора, но это привело к слишком большому стандартному коду, особенно если у вас есть много полей для настройки. Теперь я пришел к следующим решениям, которые для меня выглядят намного чище.

По сути, конкретные подклассы определяют фактические поля, которые должен поддерживать 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();
    }
}
0
rsenden