J'ai un JSON qui a un horodatage en secondes (c'est-à-dire un horodatage Unix):
{"foo":"bar","timestamp":1386280997}
Demander à Jackson de le désérialiser en un objet avec un champ DateTime pour l'horodatage donne 1970-01-17T01:11:25.983Z
, heure peu de temps après l'époque, parce que Jackson suppose qu'il est dans milliseconds . En plus de déchirer le JSON et d'ajouter des zéros, comment pourrais-je faire en sorte que Jackson comprenne les secondes horodatage?
J'ai écrit un deserializer personnalisé pour gérer les horodatages en secondes (syntaxe 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
}
}
}
Et puis j'ai annoté mon POGO pour l'utiliser pour l'horodatage:
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;
edit : suggestion de vivek-kothari
@JsonFormat(shape=JsonFormat.Shape.NUMBER, pattern="s")
public Timestamp timestamp;
Une approche très similaire à celle de @ DrewStephens utilisant l’API Java SE TimeUnit
(introduite dans JDK1.5
) au lieu de la concaténation simple String et est donc (sans doute) un peu plus propre et plus expressive:
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)));
}
}
Spécification de votre désérialiseur personnalisé (UnixTimestampDeserializer
) sur le (s) champ (s) Date
concerné (s):
@JsonDeserialize(using = UnixTimestampDeserializer.class)
private Date updatedAt;
J'ai eu ce problème exact, sauf que mes objets ZonedDateTime se sont tournés vers unix-timestamps (secondes) et que j'en avais besoin en millisecondes (pour initialiser les classes JS Date sur le navigateur).
L'implémentation d'un sérialiseur/désérialiseur personnalisé semblait trop demander pour quelque chose qui devrait être assez simple. J'ai donc cherché ailleurs et découvert que je ne pouvais que configurer le mappeur d'objets pour le résultat souhaité.
Parce que mon application remplace déjà le ObjectMapper par défaut fourni par Jersey, je devais simplement désactiver SerializationFeature.WRITE_DATE_TIMESTAMPS_AS_NANOSECONDS
.
Voici mon code
@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;
}
}
Et c'est tout