Jackson 2.8を使用していて、ISO 8601タイムスタンプ内でミリ秒を許可しないAPIと通信する必要があります。
予想される形式は次のとおりです:"2016-12-24T00:00:00Z"
WRITE_DATES_AS_TIMESTAMPS
をfalse
に設定して、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
のデフォルトのシリアライザをオーバーライドしています。
これを解決するためにいくつかの構成パラメータを使用する素敵な方法はありますか?
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();
これは、グローバルに設定できる代替案ですが、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);
}
}
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())