Java 如何从 Lombok builder 中排除财产?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/30717640/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 10:03:13  来源:igfitidea点击:

How to exclude property from Lombok builder?

javabuilderlombok

提问by Vivek Goel

I have a class called as "XYZClientWrapper" , which have following structure:

我有一个名为 "XYZClientWrapper" 的类,它具有以下结构:

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

What I want no build function generated for property XYZClient client

我不希望为财产生成任何构建函数 XYZClient client

Does Lombok supports such use case?

Lombok 是否支持这种用例?

采纳答案by Roel Spilker

Yes, you can place @Builderon a constructor or static (factory) method, containing just the fields you want.

是的,您可以将@Builder放在构造函数或静态(工厂)方法上,只包含您想要的字段。

Disclosure: I am a Lombok developer.

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

回答by Stephan

Alternatively, I found out that marking a field as final, staticor static finalinstructs @Builderto ignore this field.

或者,我发现将字段标记为finalstaticstatic final指示@Builder忽略此字段。

@Builder
public class MyClass {
   private String myField;

   private final String excludeThisField = "bar";
}

Lombok 1.16.10

龙目岛 1.16.10

回答by Bill H

Create the builder in code and add a private setter for your property.

在代码中创建构建器并为您的属性添加一个私有设置器。

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

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

回答by Richard Collette

I found that I was able to implement a "shell" of the static Builder class, add the method I want to hide with a private access modifier, and it is no longer accessible in the builder. Likewise I can add custom methods to the builder as well.

我发现我能够实现静态 Builder 类的“shell”,添加我想用私有访问修饰符隐藏的方法,并且它在构建器中不再可访问。同样,我也可以向构建器添加自定义方法。

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;
        }
    }

}

回答by SexyNerd

Here is my preferred solution. With that, you can create your field clientat the end and have it depending on other fields that previously set by the builder.

这是我的首选解决方案。这样,您可以client在最后创建您的字段,并根据构建器先前设置的其他字段来拥有它。

XYZClientWrapper{
    String name;
    String domain;
    XYZClient client;

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

回答by Youans

For factory static method example

对于工厂静态方法示例

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
   }
}

then you can use as follows:

那么你可以使用如下:

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

Noticethe static method ofwill be called whenever build() is called, so doing something like Car.builder().name("Toyota")won't actually set the value "Toyota"into nameunless build()is called and then assigning logic within the constructor static method ofis executed.

请注意of无论何时调用 build() 都会调用静态方法,因此执行类似操作Car.builder().name("Toyota")实际上不会将值设置"Toyota"name除非build()被调用,然后of执行构造函数静态方法中的分配逻辑。

Also, Noticethat the ofmethod is privately accessed so that buildmethod is the only method visible to the callers

另外,请注意of方法是私有访问的,因此该build方法是调用者可见的唯一方法

回答by kattoha

I found one more solution You can wrap your field into initiated finalwrapper or proxy. The easiest way to wrap it into AtomicReference.

我找到了另一种解决方案您可以将您的字段包装到启动的最终包装器或代理中。将其包装到 AtomicReference 中的最简单方法。

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

You can interact with it inside by get and set methods but it won't be appeared in builder.

您可以通过 get 和 set 方法在内部与它进行交互,但它不会出现在构建器中。

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

回答by Dogan Ersoz

Adding a so called 'partial builder' to the class with Lombok @Buildercan help. The trick is to add a inner partial builder class like this:

使用 Lombok 将所谓的“部分构建器”添加到类中@Builder会有所帮助。诀窍是添加一个内部部分构建器类,如下所示:

@Getter
@Builder
class Human {
    private final String name;
    private final String surname;
    private final Gender gender;
    private final String prefix; // Should be hidden, depends on gender

    // Partial builder to manage dependent fields, and hidden fields
    public static class HumanBuilder {

        public HumanBuilder gender(final Gender gender) {
            this.gender = gender;
            if (Gender.MALE == gender) {
                this.prefix = "Mr.";
            } else if (Gender.FEMALE == gender) {
                this.prefix = "Ms.";
            } else {
                this.prefix = "";
            }
            return this;
        }

        // This method hides the field from external set 
        private HumanBuilder prefix(final String prefix) {
            return this;
        }

    }

}

PS: @Builder allows the generated builder class name to be changed. The example above assumed the default builder class name is used.

PS:@Builder 允许更改生成的构建器类名。上面的例子假设使用了默认的构建器类名。