2016-11-08 94 views
10

我使用的是Jackson 2.8,需要與不允許在ISO 8601時間戳內持續幾毫秒的API進行通信。Jackson,java.time,ISO 8601,無序列化

預期的格式是這樣的:"2016-12-24T00:00:00Z"

我使用的是傑克遜的JavaTimeModule與WRITE_DATES_AS_TIMESTAMPS設置爲false

但是這會打印毫秒。

所以我試圖用objectMapper.setDateFormat哪些沒有改變任何東西。

我目前的解決方法是這樣的:

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

我重寫了Instant.class其運作默認的序列。


有沒有什麼好的方法使用一些配置參數來解決這個問題?

+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

更新:

只需添加一個@JsonFormat註釋蒙山上述Instant財產的日期格式。這很容易。

在這種情況下,你必須與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

這是這是一件好事,你可以設置全局的替代,但需要你使用ZonedDateTime即時格式化,因爲我們不能設置格式具備Instant串行Java時間模塊。

您不會看到使用zoned日期時間的任何副作用,因爲jackson會單獨序列化區域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

instantdeserializer在這裏工作嗎?真的很有趣 – Whimusical