web-dev-qa-db-ja.com

ジャクソン、Java.time、ISO 8601、ミリ秒なしでシリアル化

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

予想される形式は次のとおりです:"2016-12-24T00:00:00Z"

WRITE_DATES_AS_TIMESTAMPSfalseに設定して、JacksonのJavaTimeModuleを使用しています。

しかし、これはミリ秒を出力します。

そこで、何も変更されない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のデフォルトのシリアライザをオーバーライドしています。


これを解決するためにいくつかの構成パラメータを使用する素敵な方法はありますか?

13
Benjamin M

更新:

Instantプロパティの上に日付形式の@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();
6
Pau

これは、グローバルに設定できる代替案ですが、ZonedDateTimeシリアライザの形式を設定できないため、インスタントフォーマッタでInstantを使用する必要がありますJava時間モジュール。

ジャクソンはゾーン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);
    }
}
5
user2683814

InstantフィールドをフォーマットするKotlinコードを次に示します。ミリ秒は含まれないため、カスタム日付フォーマッターを使用できます

ObjectMapper().apply {
        val javaTimeModule = JavaTimeModule()
        javaTimeModule.addSerializer(Instant::class.Java, Iso8601WithoutMillisInstantSerializer())
        registerModule(javaTimeModule)
        disable(WRITE_DATES_AS_TIMESTAMPS)
    }

private class Iso8601WithoutMillisInstantSerializer
        : InstantSerializer(InstantSerializer.INSTANCE, false, DateTimeFormatterBuilder().appendInstant(0).toFormatter())
0
ZZ 5