【发布时间】:2018-01-18 09:42:37
【问题描述】:
我在我的项目中使用 Lombok 库,我无法在外部包中使用带有 @Builder 注释的类。
有没有办法让构建器公开?
MyClass instance = new MyClass.MyClassBuilder().build();
错误是:
'MyClassBuilder()' 在 'com.foo.MyClass.MyClassBuilder'。无法访问 外包装
【问题讨论】:
我在我的项目中使用 Lombok 库,我无法在外部包中使用带有 @Builder 注释的类。
有没有办法让构建器公开?
MyClass instance = new MyClass.MyClassBuilder().build();
错误是:
'MyClassBuilder()' 在 'com.foo.MyClass.MyClassBuilder'。无法访问 外包装
【问题讨论】:
@Builder 已经产生了公共方法,它只是包私有的构造函数。原因是他们打算让你使用静态的builder() 方法,它是公共的,而不是直接使用构造函数:
Foo foo = Foo.builder()
.property("hello, world")
.build();
如果你真的,真的,真的希望构造函数是公共的(似乎有一些建议表明其他基于反射的库可能需要它),那么 Lombok 将永远不会覆盖你的任何东西'已经显式声明了,因此您可以使用公共构造函数声明这样的骨架,Lombok 将填充其余部分,而无需将构造函数更改为包私有或任何东西。
@Builder
public class Foo
{
private final String property;
public static class FooBuilder
{
public FooBuilder() { }
// Lombok will fill in the fields and methods
}
}
这种允许部分实现覆盖默认行为的一般策略也适用于大多数(可能是所有)其他 Lombok 注释。如果您的类使用@ToString 进行注释,但您已经声明了toString 方法,它将不理会您的方法。
为了向您展示生成的所有内容,我编写了以下类:
@Builder
public class Foo
{
private final String property;
}
然后我通过delombok 运行它以查看生成的所有内容。如您所见,一切都是公开的:
public class Foo
{
private final String property;
@java.beans.ConstructorProperties({"property"})
Foo(final String property) {
this.property = property;
}
public static FooBuilder builder() {
return new FooBuilder();
}
public static class FooBuilder
{
private String property;
FooBuilder() { }
public FooBuilder property(final String property) {
this.property = property;
return this;
}
public Foo build() {
return new Foo(property);
}
public String toString() {
return "Foo.FooBuilder(property=" + this.property + ")";
}
}
}
【讨论】:
问题是你以错误的方式使用@Builder。
使用Builder Pattern时,只需要使用静态方法调用即可构建,例如:
MyClass instance = MyClass.builder().build(); 。
请不要再次newMyClassBuilder,因为您直接使用内部MyClassBuilder 类,它破坏了模式的封装。这个构造函数被隐藏在外面,这就是为什么你会得到不可访问的错误。相反,它为您提供了静态方法builder()。
【讨论】:
@ObjectFactory public UserResponse.UserResponseBuilder resolveBuilder() { return UserResponse.builder(); } 解决 mapstruct 的这个问题
我发现了这个巧妙的解决方法:
import lombok.Builder;
import lombok.Getter;
import lombok.Setter;
@Getter
@Setter
@Builder
public class Customer {
private String id;
private String name;
public static MessageBuilder builder() {return new CustomerBuilder();}
}
【讨论】:
这个构建器注解的问题是,如果你delombok你会看到,生成器的构造器没有访问指示符(公共的、私有的、受保护的),因此只能在同一个包中看到。 如果扩展类在同一个包中,这将起作用。
我遇到了同样的问题,我认为 lombok 目前不支持这个。 我可以在这里找到功能请求https://github.com/rzwitserloot/lombok/issues/1489
我的建议是在这个类中硬实现构建器模式。
【讨论】:
如前所述,您可以使用构建器,现在 builder() 将返回实例创建而不是用户属性,因此您可以将其视为普通构建器(无需使用属性)
instance = MyClass.MyClassBuilder().property1(value1).property1(value2).build();
【讨论】: