将 Jackson ObjectMapper 与 Java 8 可选值一起使用

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/25693309/
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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-11 00:56:33  来源:igfitidea点击:

Using Hymanson ObjectMapper with Java 8 Optional values

javaHymansonjava-8

提问by asieira

I was trying to use Hymanson to write a class value to JSON that has Optional as fields:

我试图使用 Hymanson 将一个类值写入具有 Optional 作为字段的 JSON:

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()));
    }
}

When executed, this class generates the following output:

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

{"field":{"present":true}}

I understand the present/not present field being included and could work around it when reading the JSON data, however I can't get around the fact that the actual content of the optional is never written to the output. :(

我了解包含的存在/不存在字段,并且在读取 JSON 数据时可以解决它,但是我无法解决可选的实际内容从未写入输出的事实。:(

Any workarounds here except not using ObjectMapper at all?

除了根本不使用 ObjectMapper 之外,还有其他解决方法吗?

采纳答案by Jonas

You could use Hymanson-datatype-jdk8which is described as:

您可以使用Hymanson-datatype-jdk8描述为:

Support for new JDK8-specific types, such as Optional

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

In order to do this:

为此:

  • add com.fasterxml.Hymanson.datatype:Hymanson-datatype-jdk8as a dependency
  • register the module with your object mapper: objectMapper.registerModule(new Jdk8Module());
  • 添加com.fasterxml.Hymanson.datatype:Hymanson-datatype-jdk8为依赖项
  • 使用您的对象映射器注册模块: objectMapper.registerModule(new Jdk8Module());

回答by Manikandan

Define new getter which will return String instead of Optional.

定义新的 getter,它将返回 String 而不是 Optional。

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

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

    @JsonProperty("field")
    public String getFieldName() {
        return field.orElse(null);
    }

}

回答by Sotirios Delimanolis

The Optionalclass has a valuefield, but no standard getter/setter for it. By default, Hymanson looks for getters/setters to find class properties.

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

You can add a custom Mixin to identify the field as a property

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

final class OptionalMixin {
    private Mixin(){}
    @JsonProperty
    private Object value;
}

and register it with your ObjectMapper.

并将其注册到您的ObjectMapper.

ObjectMapper mapper = new ObjectMapper();
mapper.addMixInAnnotations(Optional.class, OptionalMixin.class);

You can now serialize your object.

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

System.out.println(mapper.writeValueAsString(new Test()));

will print

将打印

{"field":{"value":"hello, world!","present":true}}


Consider also looking at Hymanson-datatype-guava. There's a Hymanson Moduleimplementation for Guava types including their Optional. It's possibly more complete than what I've shown above.

考虑也看Hymanson-datatype-guavaModuleGuava 类型有一个 Hymanson实现,包括它们的Optional. 它可能比我上面显示的更完整。

回答by mjj1409

Similar to @Manikandan's answer but add @JsonPropertyto the private field instead of a getter so you don't expose your work around on the public api.

类似于@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);
    }
}

回答by jiantongc

Try passing in options into @JsonIncludeannotation.
For example, if you don't want to show fieldwhen the value is null. You might need to use Hymanson-Modules >2.8.5.

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

import com.fasterxml.Hymanson.annotation.JsonInclude;

public class Test {
    @JsonInclude(JsonInclude.Include.NON_NULL)
    Optional<String> field;
}

回答by seenimurugan

If you are using latest version of Spring-boot then you could achieve this by adding the following dependency in the pom file

如果您使用的是最新版本的 Spring-boot,那么您可以通过在 pom 文件中添加以下依赖项来实现这一点

<dependency>
    <groupId>com.fasterxml.Hymanson.datatype</groupId>
    <artifactId>Hymanson-datatype-jdk8</artifactId>
</dependency>

And auto wire the HymansonObjectMapper.

并自动连接 HymansonObjectMapper。

@Autowired
private ObjectMapper HymansonObjectMapper;

Then use the above Spring container's mapper instance to convert Object to String

然后使用上面Spring容器的mapper实例将Object转为String

HymansonObjectMapper.writeValueAsString(user);

Spring blog says :

春天博客说:

Some well known Hymanson modules are automatically registered if they are detected on the classpath:

  • Hymanson-datatype-jdk7: Java 7 types like java.nio.file.Path (as of 4.2.1 release)
  • Hymanson-datatype-joda: Joda-Time types
  • Hymanson-datatype-jsr310: Java 8 Date & Time API data types
  • Hymanson-datatype-jdk8: other Java 8 types like Optional (as of 4.2.0 release)

如果在类路径上检测到一些众所周知的 Hymanson 模块,则会自动注册:

  • Hymanson-datatype-jdk7:Java 7 类型,如 java.nio.file.Path(从 4.2.1 版本开始)
  • Hymanson-datatype-joda:Joda 时间类型
  • Hymanson-datatype-jsr310:Java 8 日期和时间 API 数据类型
  • Hymanson-datatype-jdk8:其他 Java 8 类型,如 Optional(从 4.2.0 版本开始)

回答by cakraww

You only need to register module Jdk8Module. Then it will serialize any Optional<T>as Tif it is present or nullotherwise.

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

ObjectMapper objectMapper = new ObjectMapper();
objectMapper.registerModule(new Jdk8Module());

Let's modify Testclass a bit so we can test for an Optional.empty()value. This is similar to the original Testclass when serialized because the object mapper is looking for the getter (since the field is private). Using the original Testclass will work too, though.

让我们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);
    }
}

Then in our main class:

然后在我们的主类中:

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));