Lombok @Builder.Default 强制默认可选值为空

Lombok @Builder.Default forcing default Optional value to null

在我的代码中,我有一个 class 如下所示

public enum Test {
    VALUE1,
    VALUE2
}

@Builder
@AllArgsConstructor
@NoArgsConstructor
@Getter
public class MyClass {
  @JsonProperty(name = "test")
  private Optional<Test> test = Optional.empty();

}

这工作正常,但出现以下错误:

warning: @Builder will ignore the initializing expression entirely.

太好了,让我添加 @Builder.Default...

@Builder
@AllArgsConstructor
@NoArgsConstructor
@Getter
public class MyClass {
  @Builder.Default
  @JsonProperty(name = "test", required = true)
  private Optional<Test> test = Optional.empty();  
}

这修复了错误,但现在 test 值在不存在时被强制为空,而不是 Optional.empty。我想保留 Optional 模式,让对象的用户决定他们要如何处理 Optional,而不是 Lombok 或 Jackson。

有没有一种方法可以使此工作保持默认值 Optional.empty()?如果没有,有没有办法可以忽略此警告,因为它无法修复?

编辑:

假设我们将有效负载传递给某个空的端点(因为我们想测试对象中 only 值的可选值)

POST /my/end/point

有效负载为{}

然后我们使用 Jackson 取回对象

MyClass result = mapper.readValue(payload, MyClass.class);

当我们查看生成的对象时,我们会发现 MyClass.testnull 而不是使用 @Builder.Default 时预期的 Optional.empty()。否则,我们会收到上面的警告,但默认值已正确指定为 Optional.empty().

存在代码风格问题。让 Lombok 为可选字段生成 getter/setter/constructor/builder 结果:

public MyClass(Optional<Test> test) {
    this.test = test;
}

public Optional<Test> getTest() {
    return test;
}

public void setTest(Optional<Test> test) {
    this.test = test;
}

// ... imagine Builder here ...

getter还可以,但是constructor,setter,Builder用起来就很不方便了。您必须使用 Optional 上的静态方法之一包装 Test,如下所示:

// If value is known
myClass.setTest(Optional.of(Test.VALUE1));

// If initializing with a variable which maybe null
myClass.setTest(Optional.ofNullable(anotherTest));

真丑。有更好的方法。
我假设您只想要 getter 上 return 类型的 Optional,因此提供您自己的 getter 实现,强制 Lombok 不生成它自己的。

@Builder
@AllArgsConstructor
@NoArgsConstructor
@Getter
public class MyClass {

    @JsonProperty(name = "test", required = true)
    private Test test;

    public Optional<Test> getTest() {
        return Optional.ofNullable(test);
    }
}

智慧之源:Optionals and Lombok @ Medium

既然你有一个构建器,我建议切换到 @Value,使你的 class 不可变。如果要在构建对象后进行进一步更改,可以使用 toBuilder 选项。

至于说Optional setter“丑陋”的说法,我认为他们没有抓住Optional的重点。如果您整体使用 Optionals,那么进行设置的生产代码将已经有一个 optional。 setter 或 builder 参数需要它意味着调用者必须确定参数是否可以为 null。这是一件好事!调用者将不得不考虑和处理可能的空值,也许重构以便上面的层也必须提供一个可选的,等等。

实际上,可为 null 的值通常来自像 Jackson 这样的反序列化框架,它可以为您进行包装。这意味着您实际上不必经常处理“丑陋”。

永远不要仅仅因为有人说它很丑就跳过可以从代码中删除错误的东西。 Bug 少的代码是美丽的。