2016-11-08 16 views
10

私はJackson 2.8を使用しており、ISO 8601タイムスタンプ内でミリ秒を許可しないAPIと通信する必要があります。Jackson、ISO 8601、ミリ秒無しでシリアライズ

期待形式はこれです:私はfalseWRITE_DATES_AS_TIMESTAMPSセットでジャクソンのJavaTimeModuleを使用してい"2016-12-24T00:00:00Z"

しかし、これはミリ秒単位で表示されます。

だから私は何も変わっていないobjectMapper.setDateFormatを使ってみました。私は作品Instant.classのデフォルト・シリアライザをオーバーライドしてい

ObjectMapper om = new ObjectMapper(); 

DateTimeFormatter dtf = new DateTimeFormatterBuilder() 
    .appendInstant(0) 
    .toFormatter(); 

JavaTimeModule jtm = new JavaTimeModule(); 
jtm.addSerializer(Instant.class, new JsonSerializer<Instant>() { 
    @Override 
    public void serialize(Instant value, JsonGenerator gen, SerializerProvider serializers) throws IOException, JsonProcessingException { 
     gen.writeString(dtf.format(value)); 
    } 
}); 

om.registerModule(jtm); 

私の現在の回避策はこれです。


これを解決するためにいくつかの設定パラメータを使用する良い方法はありますか?

+0

フォーマットとして 'DateTimeFormatter.ISO_INSTANT'を試してみましたか? https://docs.oracle.com/javase/8/docs/api/java/time/format/DateTimeFormatter.html#ISO_INSTANT – Gelunox

+0

ターゲットAPIが制御できません。 –

+1

はい、それを試みました。ミリ秒も印刷されます。おそらくミリ秒を「0」に設定して「インスタント」を明示的に作成すると機能します。しかし、それは私のユースケースには十分安全ではありません。 **常に**直列化のためにミリ秒を無視/捨てなければなりません。 '...編集:はい、APIはいくつかの外部の会社からです。コントロールなし。 –

答えて

3

更新:

だけInstant財産上の日付形式whith @JsonFormat注釈を追加します。それは超簡単。あなたは、次のようなJavaTimeModuleとObjectMapperを持っている場合は

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

あなたはInstantプロパティを持つクラスを持っている場合は、あなたが@JsonFormat注釈を追加していないミリ秒を持っている日付パターンを配置する必要があります。それは次のようになる:だから

public static class TestDate { 

    @JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd hh:mm:ss", timezone = "UTC") 
    Instant instant; 

    //getters & setters 
} 

あなたはそれをJSONにオブジェクトをシリアライズ場合は完璧に動作します:

String json = mapper.writeValueAsString(testDate); 
System.out.println(json); 

出力

{ "インスタント": "2016から11 -10 06:03:06 "}


古い回答。理由はわかりませんが、それはうまく機能しません。

Jackson2ObjectMapperBuilderを使ってビルドすることができます。

必要なdateFormatを追加するだけです。ここで

DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss"); 

ObjectMapper mapper = Jackson2ObjectMapperBuilder 
      .json()  
      .featuresToDisable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS) 
      .modules(new JavaTimeModule()) 
      .dateFormat(dateFormat) 
      .build(); 
+0

ありがとうございます。後で試してみます:) –

+0

あなたのコードをコピー&ペーストしました。それは動作しません。それでも日付+時間+ミリ秒が得られます。 : –

+0

答えを更新しました – Pau

3

はあなたがグローバルに設定できるものである代替ですが、我々が提供Instantシリアライザの形式を設定することはできませんようインスタントフォーマッタでZonedDateTimeを使用するためにあなたを必要があります。それは次のようなものになるだろうJava Timeモジュール。

ジャンクソンがゾーンIDを別々にシリアライズし、デフォルトでは無効になっているため、ゾーニングされた日付時刻を瞬時に使用することによる副作用はありません。技術的には、これはフォーマッタをInstantに適用するのと似ています。

このように使用すると、ZonedDateTimeシリアライザはシリアル化をInstantBaseSerializerに委任し、指定されたカスタム形式を使用します。

@RunWith(JUnit4.class) 
public class InstantNoMillisTest { 

    private ObjectMapper objectMapper; 

    @Before 
    public void init() { 
     JavaTimeModule module = new JavaTimeModule(); 
     ZonedDateTimeSerializer zonedDateTimeSerializer = new ZonedDateTimeSerializer(new DateTimeFormatterBuilder().appendInstant(0).toFormatter()); 
     module.addSerializer(ZonedDateTime.class, zonedDateTimeSerializer); 
     module.addDeserializer(ZonedDateTime.class, InstantDeserializer.ZONED_DATE_TIME); 

     objectMapper = Jackson2ObjectMapperBuilder.json() 
       .modules(module) 
       .featuresToDisable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS) 
       .build(); 
    } 

    @Test 
    public void serialize() throws IOException { 
     ZonedDateTime zonedDateTime = ZonedDateTime.now(); 
     String noMillis = objectMapper.writeValueAsString(zonedDateTime); 
     System.out.print(noMillis); 
    } 

    @Test 
    public void deserialize() throws IOException { 
     String dateTime = "\"2017-10-26T12:54:59Z\""; 
     ZonedDateTime noMillis = objectMapper.readValue(dateTime, ZonedDateTime.class); 
     System.out.print(noMillis); 
    } 
} 
+0

逆順でハックする類似の方法がないので、逆シリアル化は難しい – Whimusical

+0

@Whimusicalデシリアライズテストケースを含めるための更新済みの回答 – Veeram

+0

インスタントデシリアライザはここで動作しますか? – Whimusical