J'utilise Jackson 2.8 et dois communiquer avec une API qui n'autorise pas les millisecondes dans les horodatages ISO 8601.
Le format attendu est le suivant: "2016-12-24T00:00:00Z"
J'utilise le JavaTimeModule de Jackson avec WRITE_DATES_AS_TIMESTAMPS
défini sur false
.
Mais cela imprimera des millisecondes.
J'ai donc essayé d'utiliser objectMapper.setDateFormat
qui n'a rien changé.
Ma solution actuelle est la suivante:
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);
Je remplace le sérialiseur par défaut pour Instant.class
qui fonctionne.
Existe-t-il un moyen intéressant d'utiliser un paramètre de configuration pour résoudre ce problème?
Ajoutez simplement une annotation @JsonFormat
avec le format de date au-dessus de la propriété Instant
. C'est très facile.
Dans le cas où vous avez un ObjectMapper avec le JavaTimeModule
comme suit:
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new JavaTimeModule());
Si vous avez une classe avec une propriété Instant
, vous devez ajouter l'annotation @JsonFormat
et mettre le modèle de date qui n'a pas millisecondes. Ce serait comme après:
public static class TestDate {
@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd hh:mm:ss", timezone = "UTC")
Instant instant;
//getters & setters
}
Donc si vous sérialisez un objet sur Json cela fonctionne parfaitement:
String json = mapper.writeValueAsString(testDate);
System.out.println(json);
Sortie
{"instant": "2016-11-10 06:03:06"}
Vous pouvez utiliser le Jackson2ObjectMapperBuilder
pour le construire.
Vous devez juste ajouter le dateFormat que vous voulez. Ce serait quelque chose comme:
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();
Voici une alternative que vous pouvez définir globalement, mais vous devrez utiliser ZonedDateTime
avec un formateur instantané, car nous ne pouvons pas définir le format du Instant
Serializer fourni avec Java Time Module.
L'utilisation de la date et l'heure zonées ne se produira pas instantanément car jackson sérialise l'identifiant de zone séparément et est désactivé par défaut. Donc, techniquement, cela revient à appliquer le formateur à Instant
.
Lorsqu'il est utilisé de cette manière, le sérialiseur ZonedDateTime
délègue la sérialisation à InstantBaseSerializer
et utilise le format personnalisé spécifié.
@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);
}
}
Voici un code Kotlin de mise en forme des champs Instant
, afin qu'ils ne contiennent pas des millisecondes, vous pouvez utiliser des formateurs de date personnalisés
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())