Ломбок вызывает функцию дочернего класса для построителя по умолчанию

У меня есть 2 класса, где родителю нужно какое-то свойство из дочернего класса при построении. Есть ли способ поддержать это с помощью сборщиков ломбоков?

Родительский.java

import lombok.Builder;
import lombok.Getter;
import lombok.experimental.SuperBuilder;

@Getter
@SuperBuilder
public abstract class Parent {
    @Builder.Default
    private String requestType = getRequestTypeFromSubclass();
    abstract String getRequestTypeFromSubclass();
}

Child.java

import lombok.Builder;
import lombok.Getter;
import lombok.experimental.SuperBuilder;

import java.util.List;

@Getter
@SuperBuilder
public class Child extends Parent {
    @Override
    String getRequestTypeFromSubclass() {
        return "Child1";
    }
}

Вышеприведенное не удается компилировать с сообщением

ошибка: на нестатический метод getRequestType() нельзя ссылаться из статического контекста @SuperBuilder


person best wishes    schedule 09.12.2019    source источник
comment
Это проблема, полностью сводящаяся к вопросу о том, должны ли быть abstract static методы в Java. Я считаю, что такие случаи оправдывают эту концепцию, но общая предпосылка Java по-прежнему выглядит так: «полиморфизм является характеристикой наследования объектов, а не наследования классов». (Пока нет ответа, но я проверю).   -  person TreffnonX    schedule 09.12.2019
comment
Вышеупомянутое не используется повседневно, один из вариантов использования - сериализация Джексона. подкласс выбирается на основе ключа requestType.   -  person best wishes    schedule 09.12.2019


Ответы (3)


Как предложено в Baeldung, используйте toBuilder=true и удалите @Builder.Default

import lombok.Getter;
import lombok.experimental.SuperBuilder;

@Getter
@SuperBuilder(toBuilder=true)
public abstract class Parent {

    private String requestType = getRequestType();
    abstract String getRequestType();
}

С этим мы можем избавиться от двойной инициализации

Изменить вызов построителя с помощью toBuilder, Child:

import lombok.Getter;
import lombok.experimental.SuperBuilder;
@Getter
@SuperBuilder
public class Child extends Parent {
    @Override
    String getRequestType() {
        return "Child1";
    }
    public static void main(String[] args) {
        Child child = Child.builder().build();
        System.out.println(child.getRequestType());
    }
}
person user7294900    schedule 09.12.2019
comment
@TreffnonX что такое defineRequestType() ? Вы удалили @Builder.Default? - person user7294900; 09.12.2019
comment
Я пропустил удаление @Builder.Default вместо defineRequestType. Тем не менее, код теперь дает сбой во время выполнения. Тестовый пример @Test public void test_lombokBuilderPolymorphism() { Child child1 = Child.builder().build(); assertEquals("child1", child1.getRequestType()); } завершается ошибкой при утверждении: expected: <child1> but was:<null> - person TreffnonX; 09.12.2019
comment
Изменить на new Child().toBuilder().build() - person user7294900; 09.12.2019
comment
Хм... эта строка у меня вообще не компилируется. Думаю, я делаю что-то не так. Я начинаю понимать концепцию. Однако я почему-то чувствую, что, возможно, OP лучше помочь с помощью метода инициализации ... Кроме того, я должен написать: Child child1 = new Child(Child.builder()).toBuilder().build();, чтобы он даже скомпилировался. Но это даст тот же результат во время выполнения. - person TreffnonX; 09.12.2019
comment
да, это не работает для меня. Нет .toBuilder(). @ user7294900, не могли бы вы опубликовать и родительский, и дочерний? - person best wishes; 09.12.2019
comment
@bestwishes добавили ребенка и родителя - person user7294900; 09.12.2019
comment
ааа, toBuilder=true ничего не делает, мы просто переопределили getRequestType(). если мы изменим абстрактный метод с getRequestType() на getRequestType2(), он перестанет работать. - person best wishes; 09.12.2019

Builder.Default определяется в статической области видимости, и выражение может не разрешить реализацию абстрактного метода.

Возможно, вы захотите попробовать это вместо этого:

@Getter
@SuperBuilder
public abstract class Parent {

    private String reqType;
    abstract String getRequestType();

    public String getReqType() {
        return Objects.isNull(reqType) ? getRequestType() : reqType;
    }
}

Переопределите метод свойства с именем метода, отличным от фактического метода получения атрибута, и это должно решить проблему.

Попробуйте с:

Parent parent = Child.builder().build();
person Mohamed Saligh    schedule 09.12.2019

Хотя ломбок — отличный инструмент для решения многих задач, в данном случае вы, возможно, захотите избежать использования шаблона построителя. Желаемый эффект (доступ к дочернему методу во время родительской инициализации возможен внутри стандартных конструкторов POJO. Для меня работает следующее:

@Getter
public abstract class Parent {
    private String requestType = defineRequestType();

    protected abstract String defineRequestType();
}

@Getter
public class Child extends Parent {
    protected String defineRequestType() {
        return "child1";
    }
}

и следующий тестовый пример:

@Test
public void test_lombokBuilderPolymorphism() {
    Child child1 = new Child();
    assertEquals("child1", child1.getRequestType());
}

Поэтому, если вам определенно не требуется шаблон Builder по каким-либо другим причинам, возможностей POJO по умолчанию здесь достаточно.

На заметку: вы должны назвать определяющий метод, отличный от get..., чтобы он не сталкивался с сгенерированным геттером (getRequestType).

person TreffnonX    schedule 09.12.2019