Java Jackson 在 Spring Boot 中错误地序列化了 ZonedDateTime

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

Hymanson serializes a ZonedDateTime wrongly in Spring Boot

javajsonspring-bootHymansonzoneddatetime

提问by jbx

I have a simple application with Spring Boot and Jetty. I have a simple controller returning an object which has a Java 8 ZonedDateTime:

我有一个带有 Spring Boot 和 Jetty 的简单应用程序。我有一个简单的控制器返回一个具有 Java 8 的对象ZonedDateTime

public class Device {
  // ...
  private ZonedDateTime lastUpdated;

  public Device(String id, ZonedDateTime lastUpdated, int course, double latitude, double longitude) {
    // ...
    this.lastUpdated = lastUpdated;
    // ...
  }

  public ZonedDateTime getLastUpdated() {
    return lastUpdated;
  }
}

In my RestControllerI simply have:

在我的RestController我只是:

@RequestMapping("/devices/")
public @ResponseBody List<Device> index() {
  List<Device> devices = new ArrayList<>();
  devices.add(new Device("321421521", ZonedDateTime.now(), 0, 39.89011333, 24.438176666));

  return devices;
}

I was expecting the ZonedDateTimeto be formatted according to the ISO format, but instead I am getting a whole JSON dump of the class like this:

我期待ZonedDateTime根据 ISO 格式对它进行格式化,但是我得到了该类的整个 JSON 转储,如下所示:

"lastUpdated":{"offset":{"totalSeconds":7200,"id":"+02:00","rules":{"fixedOffset":true,"transitionRules":[],"transitions":[]}},"zone":{"id":"Europe/Berlin","rules":{"fixedOffset":false,"transitionRules":[{"month":"MARCH","timeDefinition":"UTC","standardOffset":{"totalSeconds":3600,"id":"+01:00","rules":{"fixedOffset":true,"transitionRules":[],"transitions":[]}},"offsetBefore":{"totalSeconds":3600,"id":"+01:00","rules":{"fixedOffset":true,"transitionRules":[],"transitions":[]}},"offsetAfter":{"totalSeconds":7200,"id":"+02:00", ...

I just have a spring-boot-starter-webapplication, using spring-boot-starter-jettyand excluding spring-boot-starter-tomcat.

我只有一个spring-boot-starter-web应用程序,使用spring-boot-starter-jetty和排除spring-boot-starter-tomcat.

Why is Hymanson behaving like this in Spring Boot?

为什么Hyman逊在 Spring Boot 中表现如此?

** UPDATE **

** 更新 **

For those looking for a full step by step guide how to solve this I found this after asking the question: http://lewandowski.io/2016/02/formatting-java-time-with-spring-boot-using-json/

对于那些正在寻找如何解决这个问题的完整分步指南的人,我在提出问题后发现了这一点:http: //lewandowski.io/2016/02/formatting-java-time-with-spring-boot-using-json/

采纳答案by vsminkov

There is a library Hymanson-datatype-jsr310. Try it.

有一个库Hymanson-datatype-jsr310。尝试一下。

This library covers new datetime API and includes serializers for ZonedDateTimetoo.

这个库涵盖了新的日期时间 API,也包括序列化程序ZonedDateTime

All you need is just to add JavaTimeModule:

您只需要添加JavaTimeModule

ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new JavaTimeModule());

UPDATE

更新

To convert datetime to ISO-8601string you should disable WRITE_DATES_AS_TIMESTAMPSfeature. You can easily do by either overriding ObjectMapperbean or by using application properties:

要将日期时间转换为ISO-8601字符串,您应该禁用WRITE_DATES_AS_TIMESTAMPS功能。您可以通过覆盖ObjectMapperbean 或使用应用程序属性轻松完成:

spring.Hymanson.serialization.WRITE_DATES_AS_TIMESTAMPS = false

回答by bpawlowski

If you either don't rely on SpringBoot's auto-configuration feature - you don't provide spring.Hymanson.serialization.WRITE_DATES_AS_TIMESTAMPS = falseproperty into your configuration file - or for whatever reason you create ObjectMapperinstance manually. You can disable this feature programatically as follows:

如果您不依赖 SpringBoot 的自动配置功能 - 您没有spring.Hymanson.serialization.WRITE_DATES_AS_TIMESTAMPS = false在配置文件中提供属性 - 或者出于任何原因ObjectMapper手动创建实例。您可以按如下方式以编程方式禁用此功能:

ObjectMapper m = new ObjectMapper();
m.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);

this is for Hymanson 2.8.7

这是给Hyman逊的 2.8.7

回答by UltimaWeapon

The answer was already mentioned above but I think it's missing some info. For those looking to parse Java 8 timestamps in many forms (not just ZonedDateTime). You need a recent version of Hymanson-datatype-jsr310in your POM and have the following module registered:

上面已经提到了答案,但我认为它缺少一些信息。对于那些希望以多种形式(不仅仅是 ZonedDateTime)解析 Java 8 时间戳的人。您需要Hymanson-datatype-jsr310在 POM 中使用最新版本并注册以下模块:

ObjectMapper objectMapper = new ObjectMapper();
objectMapper.registerModule(new JavaTimeModule());
objectMapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);

To test this code

要测试此代码

@Test
void testSeliarization() throws IOException {
    String expectedJson = "{\"parseDate\":\"2018-12-04T18:47:38.927Z\"}";
    MyPojo pojo = new MyPojo(ZonedDateTime.parse("2018-12-04T18:47:38.927Z"));

    // serialization
    assertThat(objectMapper.writeValueAsString(pojo)).isEqualTo(expectedJson);

    // deserialization
    assertThat(objectMapper.readValue(expectedJson, MyPojo.class)).isEqualTo(pojo);
}

Note that you can configure your object mapper globally in Spring or dropwizard to achieve this. I have not yet found a clean way to do this as an annotation on a field without registering a custom (de)serializer.

请注意,您可以在 Spring 或 dropwizard 中全局配置对象映射器来实现此目的。我还没有找到一种干净的方法来在不注册自定义(反)序列化程序的情况下将其作为字段上的注释。

回答by Somu

For Hymanson 2.10and above,

对于Hyman逊2.10及以上,

parent pom.xml

父 pom.xml

<!-- https://github.com/FasterXML/Hymanson-bom -->
<dependencyManagement>
  <dependency>
    <groupId>com.fasterxml.Hymanson</groupId>
    <artifactId>Hymanson-bom</artifactId>
    <version>2.10.3</version>
    <type>pom</type>
    <scope>import</scope>
  </dependency>
</dependencyManagement>

module pom.xml

模块 pom.xml

<!-- https://github.com/FasterXML/Hymanson-modules-java8 -->
<dependency>
    <groupId>com.fasterxml.Hymanson.datatype</groupId>
    <artifactId>Hymanson-datatype-jsr310</artifactId>
</dependency>

JsonMapper creation, possibly in your @Configurationclass

JsonMapper 创建,可能在你的@Configuration课堂上

@Bean
public JsonMapper jsonMapper() {
    return JsonMapper.builder()
        .configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false)
        .addModule(new JavaTimeModule())
        .build();
}

Further reading:

进一步阅读: