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
How to exclude property from Lombok builder?
提问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
回答by Stephan
Alternatively, I found out that marking a field as final, staticor static finalinstructs @Builder
to ignore this field.
或者,我发现将字段标记为final、static或static 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 client
at 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 of
will be called whenever build() is called, so doing something like Car.builder().name("Toyota")
won't actually set the value "Toyota"
into name
unless build()
is called and then assigning logic within the constructor static method of
is executed.
请注意,of
无论何时调用 build() 都会调用静态方法,因此执行类似操作Car.builder().name("Toyota")
实际上不会将值设置"Toyota"
为name
除非build()
被调用,然后of
执行构造函数静态方法中的分配逻辑。
Also, Noticethat the of
method is privately accessed so that build
method 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 @Builder
can 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 允许更改生成的构建器类名。上面的例子假设使用了默认的构建器类名。