【问题标题】:Lombok @Builder.Default forcing default Optional value to nullLombok @Builder.Default 强制默认 Optional 值为 null
【发布时间】:2018-03-29 23:50:22
【问题描述】:

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

public enum Test {
    VALUE1,
    VALUE2
}

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

}

这工作正常,但它给出了以下错误:

警告:@Builder 将完全忽略初始化表达式。

太好了,让我添加@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()

【问题讨论】:

  • 我想我是“那个人”,他宁愿编写样板代码也不愿使用需要和 IDE 插件的第三方工具(实际上随时可能失去支持)为我做事。你只是设法降低了我使用 Lombok 的欲望。
  • @JacobBlanton 感谢您的反馈,但是编写样板文件容易出错。在我作为开发人员的这些年里,我可以将许多非常愚蠢的错误归因于编写样板的复制/粘贴性质。也许你永远保持警惕,但我肯定不是。这些库受欢迎是有原因的,您可能想再给他们一次机会。

标签: java-8 jackson optional lombok


【解决方案1】:

存在代码样式问题。让 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));

太丑了。有更好的方法。
我假设你只想要 Optional 作为 getter 的返回类型,所以提供你自己的 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

【讨论】:

  • 我选择了这个作为答案,但我不得不取消选择它。这是一篇很棒的文章,但我认为杰克逊使用的二传手存在问题。在这种情况下,我们需要找到一种方法来生成一个新的 setter,将值设置为 null 以外的值(当然,null 来自 jackson)。如果你完成它,我会标记你的答案,以便示例有效负载返回预期的结果(将在一秒钟内更新帖子)。
【解决方案2】:

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

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

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

永远不要仅仅因为有人说它丑陋而跳过可以从代码中删除错误的东西。错误少的代码很漂亮。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-07-28
    • 1970-01-01
    • 2012-01-18
    • 2018-11-17
    • 1970-01-01
    • 2023-01-17
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多