web-dev-qa-db-ja.com

Jacksonの秒単位のタイムスタンプをデシリアライズするにはどうすればよいですか?

秒単位のタイムスタンプ(つまりUnixタイムスタンプ)を持つJSONをいくつか持っています:

{"foo":"bar","timestamp":1386280997}

タイムスタンプのDateTimeフィールドを持つオブジェクトにこれを逆シリアル化するようにJacksonに依頼すると、1970-01-17T01:11:25.983Z、エポックのすぐ後の時間。ジャクソンはミリ秒であると想定しているためです。 JSONをリッピングしてゼロを追加する以外に、ジャクソンにsecondsタイムスタンプを理解させるにはどうすればよいですか?

27
Drew Stephens

タイムスタンプを秒単位で処理するために、カスタム デシリアライザー を作成しました(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
    }
}
25
Drew Stephens
@JsonFormat(shape=JsonFormat.Shape.STRING, pattern="s")
public Date timestamp;

編集:vivek-kothariの提案

@JsonFormat(shape=JsonFormat.Shape.NUMBER, pattern="s")
public Timestamp timestamp;
14
sherpya

Java SE TimeUnit AP​​Iを使用する@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;
8
Priidu Neemre

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

以上です

1
svarog