使用Jackson ObjectMapper和Java 8可选值

asi*_*ira 50 java jackson java-8

我试图使用Jackson将类值写入JSON,其中包含Optional作为字段:

public class Test {
    Optional<String> field = Optional.of("hello, world!");

    public Optional<String> getField() {
        return field;
    }

    public static void main(String[] args) throws JsonProcessingException {
        ObjectMapper mapper = new ObjectMapper();
        System.out.println(mapper.writeValueAsString(new Test()));
    }
}
Run Code Online (Sandbox Code Playgroud)

执行时,此类生成以下输出:

{"field":{"present":true}}
Run Code Online (Sandbox Code Playgroud)

我理解当前/不存在的字段被包含在内并且可以在读取JSON数据时解决它,但是我无法解决可选的实际内容永远不会写入输出的事实.:(

除了不使用ObjectMapper之外,这里有任何变通方法吗?

Jon*_*nas 59

您可以使用jackson-datatype-jdk8,其描述如下:

支持新的JDK8特定类型,例如Optional

  • 你还需要注册一个像```ObjectMapper objectMapper = new ObjectMapper(); objectMapper.registerModule(new Jdk8Module());``` (8认同)
  • 根据链接的GitHub存储库:`注意:此模块已成为杰克逊2.8.5中Jackson Java 8模块的一部分.此存储库仍然存在,允许发布旧版本的补丁版本; 它将在不久的将来被隐藏(私有化) (5认同)

Sot*_*lis 13

Optional班有一个value领域,但它没有标准的getter/setter.默认情况下,杰克逊寻找getter/setter来查找类属性.

您可以添加自定义Mixin以将该字段标识为属性

final class OptionalMixin {
    private Mixin(){}
    @JsonProperty
    private Object value;
}
Run Code Online (Sandbox Code Playgroud)

并将其注册到您的ObjectMapper.

ObjectMapper mapper = new ObjectMapper();
mapper.addMixInAnnotations(Optional.class, OptionalMixin.class);
Run Code Online (Sandbox Code Playgroud)

您现在可以序列化您的对象.

System.out.println(mapper.writeValueAsString(new Test()));
Run Code Online (Sandbox Code Playgroud)

将打印

{"field":{"value":"hello, world!","present":true}}
Run Code Online (Sandbox Code Playgroud)

考虑一下jackson-datatype-guava.有一个杰克逊Module实施的番石榴类型,包括他们的Optional.它可能比我上面所示的更完整.


mjj*_*409 9

类似于@Manikandan的回答,但是添加@JsonProperty到私有字段而不是getter,所以你不要在公共api上公开你的工作.

public class Test {

    @JsonProperty("field")
    private String field;

    @JsonIgnore
    public Optional<String> getField() {
        return Optional.of(field); // or Optional.ofNullable(field);
    }
}
Run Code Online (Sandbox Code Playgroud)


cak*_*aww 6

您只需要注册module Jdk8Module。然后,它将序列化任何序列Optional<T>,就T好像它是否存在一样null

ObjectMapper objectMapper = new ObjectMapper();
objectMapper.registerModule(new Jdk8Module());
Run Code Online (Sandbox Code Playgroud)

让我们Test稍微修改一下类,以便测试一个Optional.empty()值。这与Test序列化时的原始类相似,因为对象映射器正在寻找getter(因为该字段是private)。但是,使用原始Test类也可以。

class Test {
    private final String field;

    public Test(String field) {
        this.field = field;
    }

    public Optional<String> getField() {
        return Optional.ofNullable(field);
    }
}
Run Code Online (Sandbox Code Playgroud)

然后在我们的主要班级:

Test testFieldNull = new Test(null);
Test testFieldNotNull = new Test("foo");

// output: {"field":null}
System.out.println(objectMapper.writeValueAsString(testFieldNull)); 

// output: {"field":"foo"}
System.out.println(objectMapper.writeValueAsString(testFieldNotNull)); 
Run Code Online (Sandbox Code Playgroud)


jia*_*ngc 5

尝试将选项传递到@JsonInclude注释中。
例如,如果您不想显示field值何时为null您可能需要使用 Jackson-Modules >2.8.5

import com.fasterxml.jackson.annotation.JsonInclude;

public class Test {
    @JsonInclude(JsonInclude.Include.NON_NULL)
    Optional<String> field;
}
Run Code Online (Sandbox Code Playgroud)