秒単位のタイムスタンプ(つまりUnixタイムスタンプ)を持つJSONをいくつか持っています:
{"foo":"bar","timestamp":1386280997}
タイムスタンプのDateTimeフィールドを持つオブジェクトにこれを逆シリアル化するようにJacksonに依頼すると、1970-01-17T01:11:25.983Z
、エポックのすぐ後の時間。ジャクソンはミリ秒であると想定しているためです。 JSONをリッピングしてゼロを追加する以外に、ジャクソンにsecondsタイムスタンプを理解させるにはどうすればよいですか?
タイムスタンプを秒単位で処理するために、カスタム デシリアライザー を作成しました(Groovy構文)。
class UnixTimestampDeserializer extends JsonDeserializer<DateTime> {
Logger logger = LoggerFactory.getLogger(UnixTimestampDeserializer.class)
@Override
DateTime deserialize(JsonParser jp, DeserializationContext ctxt) throws IOException, JsonProcessingException {
String timestamp = jp.getText().trim()
try {
return new DateTime(Long.valueOf(timestamp + '000'))
} catch (NumberFormatException e) {
logger.warn('Unable to deserialize timestamp: ' + timestamp, e)
return null
}
}
}
そして、POGOに注釈を付けてタイムスタンプに使用します。
class TimestampThing {
@JsonDeserialize(using = UnixTimestampDeserializer.class)
DateTime timestamp
@JsonCreator
public TimestampThing(@JsonProperty('timestamp') DateTime timestamp) {
this.timestamp = timestamp
}
}
@JsonFormat(shape=JsonFormat.Shape.STRING, pattern="s")
public Date timestamp;
編集:vivek-kothariの提案
@JsonFormat(shape=JsonFormat.Shape.NUMBER, pattern="s")
public Timestamp timestamp;
Java SE TimeUnit
APIを使用する@DrewStephensのアプローチと非常によく似たアプローチ(JDK1.5
)単純なString連結の代わりに、したがって(ほぼ間違いなく)少し簡潔で表現力豊かです。
public class UnixTimestampDeserializer extends JsonDeserializer<Date> {
@Override
public Date deserialize(JsonParser parser, DeserializationContext context)
throws IOException, JsonProcessingException {
String unixTimestamp = parser.getText().trim();
return new Date(TimeUnit.SECONDS.toMillis(Long.valueOf(unixTimestamp)));
}
}
影響を受けるUnixTimestampDeserializer
フィールドでカスタムデシリアライザー(Date
)を指定する:
@JsonDeserialize(using = UnixTimestampDeserializer.class)
private Date updatedAt;
ZonedDateTimeオブジェクトがunix-timestamps(秒)になり、ミリ秒単位で(ブラウザーでJS Dateオブジェクトを初期化するために)必要になることを除いて、この正確な問題がありました。
カスタムシリアライザー/デシリアライザーの実装は、非常に単純なものにはあまりにも多くの作業のように見えたので、他の場所を見て、目的の結果に合わせてオブジェクトマッパーを構成できることを発見しました。
私のアプリケーションはすでにJerseyが提供するデフォルトのObjectMapperをオーバーライドしているため、 SerializationFeature.WRITE_DATE_TIMESTAMPS_AS_NANOSECONDS
。
これが私のコードです
@Provider
public class RPObjectMapperProvider implements ContextResolver<ObjectMapper> {
final ObjectMapper defaultObjectMapper;
public RPObjectMapperProvider() {
defaultObjectMapper = new ObjectMapper();
// this turned ZonedDateTime objects to proper seconds timestamps
defaultObjectMapper.enable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
// disable to serialize dates for millis timestamps
defaultObjectMapper.disable(SerializationFeature.WRITE_DATE_TIMESTAMPS_AS_NANOSECONDS);
// using Java8 date time classes
defaultObjectMapper.registerModule(new JavaTimeModule());
}
@Override
public ObjectMapper getContext(Class<?> type) {
return defaultObjectMapper;
}
}
以上です