web-dev-qa-db-fra.com

Comment sérialiser Joda DateTime avec le processeur Jackson JSON?

Comment faire en sorte que Jackson sérialise mon objet Joda DateTime selon un modèle simple (comme "jj-MM-aaaa")?

J'ai essayé:

@JsonSerialize(using=DateTimeSerializer.class)
private final DateTime date;

J'ai aussi essayé:

ObjectMapper mapper = new ObjectMapper()
    .getSerializationConfig()
    .setDateFormat(df);

Merci!

114
Haywood Jablomey

Cela est devenu très facile avec Jackson 2.0 et le module Joda.

ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new JodaModule());

Dépendance Maven:

<dependency>
  <groupId>com.fasterxml.jackson.datatype</groupId>
  <artifactId>jackson-datatype-joda</artifactId>
  <version>2.1.1</version>
</dependency>  

Code et documentation: https://github.com/FasterXML/jackson-datatype-joda

Fichiers binaires: http://repo1.maven.org/maven2/com/fasterxml/jackson/datatype/jackson-datatype-joda/

138
Kimble

Dans l'objet que vous mappez:

@JsonSerialize(using = CustomDateSerializer.class)
public DateTime getDate() { ... }

Dans CustomDateSerializer:

public class CustomDateSerializer extends JsonSerializer<DateTime> {

    private static DateTimeFormatter formatter = 
        DateTimeFormat.forPattern("dd-MM-yyyy");

    @Override
    public void serialize(DateTime value, JsonGenerator gen, 
                          SerializerProvider arg2)
        throws IOException, JsonProcessingException {

        gen.writeString(formatter.print(value));
    }
}
74
Rusty Kuntz

Comme l'a dit @ Kimble, avec Jackson 2, l'utilisation du formatage par défaut est très simple. enregistrez simplement JodaModule sur votre ObjectMapper.

ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new JodaModule());

Pour la sérialisation/désérialisation personnalisée de DateTime, vous devez implémenter vos propres StdScalarSerializer et StdScalarDeserializer; c'est assez compliqué, mais quand même.

Par exemple, voici un sérialiseur DateTime qui utilise le ISODateFormat avec le fuseau horaire UTC:

public class DateTimeSerializer extends StdScalarSerializer<DateTime> {

    public DateTimeSerializer() {
        super(DateTime.class);
    }

    @Override
    public void serialize(DateTime dateTime,
                          JsonGenerator jsonGenerator,
                          SerializerProvider provider) throws IOException, JsonGenerationException {
        String dateTimeAsString = ISODateTimeFormat.withZoneUTC().print(dateTime);
        jsonGenerator.writeString(dateTimeAsString);
    }
}

Et le dé-sérialiseur correspondant:

public class DateTimeDesrializer extends StdScalarDeserializer<DateTime> {

    public DateTimeDesrializer() {
        super(DateTime.class);
    }

    @Override
    public DateTime deserialize(JsonParser jsonParser,
                                DeserializationContext deserializationContext) throws IOException, JsonProcessingException {
        try {
            JsonToken currentToken = jsonParser.getCurrentToken();
            if (currentToken == JsonToken.VALUE_STRING) {
                String dateTimeAsString = jsonParser.getText().trim();
                return ISODateTimeFormat.withZoneUTC().parseDateTime(dateTimeAsString);
            }
        } finally {
            throw deserializationContext.mappingException(getValueClass());
        }
    }

Ensuite, liez-les avec un module:

public class DateTimeModule extends SimpleModule {

    public DateTimeModule() {
        super();
        addSerializer(DateTime.class, new DateTimeSerializer());
        addDeserializer(DateTime.class, new DateTimeDeserializer());
    }
}

Puis enregistrez le module sur votre ObjectMapper:

ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new DateTimeModule());
22
oggmonster

https://stackoverflow.com/a/10835114/111351

Bien que vous puissiez mettre une annotation pour chaque champ de date, il est préférable d’effectuer une configuration globale pour votre mappeur d’objets. Si vous utilisez Jackson, vous pouvez configurer votre ressort comme suit:

<bean id="jacksonObjectMapper" class="com.company.CustomObjectMapper" />

<bean id="jacksonSerializationConfig" class="org.codehaus.jackson.map.SerializationConfig"
    factory-bean="jacksonObjectMapper" factory-method="getSerializationConfig" >
</bean>

Pour CustomObjectMapper:

public class CustomObjectMapper extends ObjectMapper {

    public CustomObjectMapper() {
        super();
        configure(Feature.WRITE_DATES_AS_TIMESTAMPS, false);
        setDateFormat(new SimpleDateFormat("EEE MMM dd yyyy HH:mm:ss 'GMT'ZZZ (z)"));
    }
}

Bien entendu, SimpleDateFormat peut utiliser n’importe quel format.

15
Moesio

La solution facile

J'ai rencontré un problème similaire et ma solution est beaucoup plus claire que ci-dessus.

j'ai simplement utilisé le motif dans@JsonFormatannotation

Fondamentalement, ma classe a un champ DateTime, alors je mets une annotation autour du getter:

@JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
public DateTime getDate() {
    return date;
}

Je sérialise la classe avec ObjectMapper

    ObjectMapper mapper = new ObjectMapper();
    mapper.registerModule(new JodaModule());
    mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
    ObjectWriter ow = mapper.writer();
    try {
        String logStr = ow.writeValueAsString(log);
        outLogger.info(logStr);
    } catch (IOException e) {
        logger.warn("JSON mapping exception", e);
    }

Nous utilisons Jackson 2.5.4

15
Atais

Pendant ce temps, Jackson enregistre automatiquement le module Joda lorsque JodaModule est dans classpath. Je viens d'ajouter jackson-datatype-joda à Maven et cela a fonctionné instantanément.

<dependency>
  <groupId>com.fasterxml.jackson.datatype</groupId>
  <artifactId>jackson-datatype-joda</artifactId>
  <version>2.8.7</version>
</dependency>

Sortie JSON:

{"created" : "2017-03-28T05:59:27.258Z"}
8
Stephan

Pour ceux avec Spring Boot, vous devez ajouter le module à votre contexte et il sera ajouté à votre configuration comme ceci.

@Bean
public Module jodaTimeModule() {
    return new JodaModule();
}

Et si vous souhaitez utiliser le nouveau module horaire Java8, jsr-310.

@Bean
public Module jodaTimeModule() {
    return new JavaTimeModule();
}
5
jgeerts

Il semble que pour Jackson 1.9.12, une telle possibilité n'existe pas par défaut, à cause de:

public final static class DateTimeSerializer
    extends JodaSerializer<DateTime>
{
    public DateTimeSerializer() { super(DateTime.class); }

    @Override
    public void serialize(DateTime value, JsonGenerator jgen, SerializerProvider provider)
        throws IOException, JsonGenerationException
    {
        if (provider.isEnabled(SerializationConfig.Feature.WRITE_DATES_AS_TIMESTAMPS)) {
            jgen.writeNumber(value.getMillis());
        } else {
            jgen.writeString(value.toString());
        }
    }

    @Override
    public JsonNode getSchema(SerializerProvider provider, Java.lang.reflect.Type typeHint)
    {
        return createSchemaNode(provider.isEnabled(SerializationConfig.Feature.WRITE_DATES_AS_TIMESTAMPS)
                ? "number" : "string", true);
    }
}

Cette classe sérialise les données à l'aide de la méthode toString () de Joda DateTime.

L'approche proposée par Rusty Kuntz fonctionne parfaitement pour mon cas.

3
ydrozhdzhal

J'utilise Java 8 et cela a fonctionné pour moi:

ajouter la dépendance sur pom.xml
<dependency> <groupId>com.fasterxml.jackson.datatype</groupId> <artifactId>jackson-datatype-jsr310</artifactId> <version>2.4.0</version> </dependency>

et ajoutez JodaModule sur votre ObjectMapper
ObjectMapper mapper = new ObjectMapper(); mapper.registerModule(new JodaModule());

2
Luciana Campello