web-dev-qa-db-ja.com

ジャクソンは、Spring Bootで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;
  }
}

私の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;
}

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", ...

spring-boot-starter-webを使用し、spring-boot-starter-jettyを除くspring-boot-starter-Tomcatアプリケーションがあります。

なぜジャクソンはSpring Bootでこのように振る舞いますか?

**更新**

これを解決する方法をステップバイステップガイドで探している人のために、私は質問をした後にこれを見つけました: http://lewandowski.io/2016/02/formatting-Java-time-with-spring-boot- using-json /

26
jbx

ライブラリがあります jackson-datatype-jsr31 。それを試してみてください。

このライブラリは、新しい日時APIをカバーし、ZonedDateTimeのシリアライザーも含まれています。

必要なのはJavaTimeModuleを追加するだけです:

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

[〜#〜] update [〜#〜]

日時を ISO-8601 文字列に変換するには、 WRITE_DATES_AS_TIMESTAMPS 機能を無効にする必要があります。 ObjectMapper Beanをオーバーライドするか、 アプリケーションプロパティ を使用することで簡単に実行できます。

spring.jackson.serialization.WRITE_DATES_AS_TIMESTAMPS = false
41
vsminkov

SpringBootの自動設定機能に依存しない場合-spring.jackson.serialization.WRITE_DATES_AS_TIMESTAMPS = falseプロパティを設定ファイルに-または何らかの理由でObjectMapperインスタンスを手動で作成します。この機能は、次のようにプログラムで無効にできます。

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

これはジャクソン用です2.8.7

3
bpawlowski

答えはすでに上で述べたが、情報が欠けていると思う。 Java ZonedDateTimeだけでなく、多くの形式の8つのタイムスタンプ)を解析する場合。POMにjackson-datatype-jsr310の最新バージョンが必要で、次のモジュールを登録してください。

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

このコードをテストするには

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

これを実現するために、SpringまたはDropwizardでオブジェクトマッパーをグローバルに構成できることに注意してください。カスタム(デ)シリアライザーを登録せずに、フィールドの注釈としてこれを行うクリーンな方法をまだ見つけていません。

2
UltimaWeapon