Как исключить недвижимость из Ломбок застройщика?

У меня есть класс, называемый "XYZClientWrapper", который имеет следующую структуру:

@Builder
XYZClientWrapper{
    String name;
    String domain;
    XYZClient client;
}

Что я хочу, чтобы функция построения, сгенерированная для свойства XYZClient client

Поддерживает ли Lombok такой вариант использования?

Ответ 1

Да, вы можете поместить @Builder в конструктор или статический (заводский) метод, содержащий только нужные поля.

Раскрытие информации: Я разработчик Lombok.

Ответ 2

В качестве альтернативы я обнаружил, что маркирование поля как окончательного, статического или статического окончательного инструктирует @Builder игнорировать это поле.

@Builder
public class MyClass {
   private String myField;

   private final String excludeThisField = "bar";
}

Ломбок 1.16.10

Ответ 3

Я обнаружил, что мне удалось реализовать "оболочку" статического класса Builder, добавить метод, который я хочу скрыть с помощью модификатора частного доступа, и он больше не доступен в построителе. Кроме того, я могу добавить собственные методы для строителя.

package com.something;

import lombok.AccessLevel;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;

import javax.persistence.AttributeOverride;
import javax.persistence.AttributeOverrides;
import javax.persistence.Column;
import javax.persistence.Embedded;
import javax.persistence.Entity;
import java.time.ZonedDateTime;

@Data
@Entity
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class MyClass{

    //The builder will generate a method for this property for us.
    private String anotherProperty;

    @Embedded
    @AttributeOverrides({
            @AttributeOverride(name = "localDateTime", column = @Column(name = "some_date_local_date_time")),
            @AttributeOverride(name = "zoneId", column = @Column(name = "some__date_zone_id"))
    })
    @Getter(AccessLevel.PRIVATE)
    @Setter(AccessLevel.PRIVATE)
    private ZonedDateTimeEmbeddable someDateInternal;

    public ZonedDateTime getSomeDate() {
        return someDateInternal.toZonedDateTime();
    }

    public void setSomeDate(ZonedDateTime someDate) {
        someDateInternal = new ZonedDateTimeEmbeddable(someDate);
    }

    public static class MyClassBuilder {
        //Prevent direct access to the internal private field by pre-creating builder method with private access.
        private MyClassBuilder shipmentDateInternal(ZonedDateTimeEmbeddable zonedDateTimeEmbeddable) {
            return this;
        }

        //Add a builder method because we don't have a field for this Type
        public MyClassBuilder someDate(ZonedDateTime someDate) {
            someDateInternal = new ZonedDateTimeEmbeddable(someDate);
            return this;
        }
    }

}

Ответ 4

Создайте конструктор в коде и добавьте частный сеттер для вашего свойства.

@Builder
XYZClientWrapper{
    String name;
    String domain;
    XYZClient client;

    public static class XYZClientWrapperBuilder {
        private XYZClientWrapperBuilder client(XYZClient client) { return this; }
    }
}

Ответ 5

Вот мое предпочтительное решение. При этом вы можете создать своего client в конце и иметь его в зависимости от других полей, которые ранее устанавливались разработчиком.

XYZClientWrapper{
    String name;
    String domain;
    XYZClient client;

    @Builder
    public XYZClientWrapper(String name, String domain) {
        this.name=name;this.domain=domain;
        this.client=calculateClient();
    }
}

Ответ 6

Для заводского статического метода, пример

class Car{
   private String name;
   private String model;


   private Engine engine; // we want to ignore setting this

   @Builder
   private static Car of(String name, String model){
      Car car=new Car();
      car.name = name;
      car.model = model;
      constructEngine(car); // some static private method to construct engine internally
      return car;  
   }

   private static void constructEngine(Car car) {
       // car.engine = blabla...
       // construct engine internally
   }
}

тогда вы можете использовать следующее:

Car toyotaCorollaCar=Car.builder().name("Toyota").model("Corolla").build();
// You can see now that Car.builder().engine() is not available

Обратите внимание, статический метод of будет вызываться всякий раз, когда вызывается build(), поэтому выполнение чего-то вроде Car.builder().name("Toyota") фактически не установит значение "Toyota" в name, если не вызывается build() и затем выполняется назначение логики в статическом методе конструктора of.

Кроме того, обратите внимание, что метод of доступен для частного доступа, так что метод build является единственным методом, видимым для вызывающих

Ответ 7

Я нашел еще одно решение Вы можете заключить свое поле в инициированную финальную оболочку или прокси. Самый простой способ обернуть его в AtomicReference.

@Builder
public class Example {
    private String field1;
    private String field2;
    private final AtomicReference<String> excluded = new AtomicReference<>(null);
}

Вы можете взаимодействовать с ним внутри с помощью методов get и set, но он не будет отображаться в компоновщике.

excluded.set("Some value");
excluded.get();