Wie serialisiere ich Joda DateTime mit dem Jackson JSON-Prozessor?


118

Wie bringe ich Jackson dazu, mein Joda DateTime-Objekt nach einem einfachen Muster (wie "TT-MM-JJJJ") zu serialisieren?

Ich habe es versucht:

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

Ich habe auch versucht:

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

Vielen Dank!


Beides sollte eigentlich auch funktionieren (@JsonSerialize sollte bedeuten, dass das Feld serialisiert werden soll; und das Datumsformat sollte idealerweise auch für Joda gelten) . Daher möchten Sie möglicherweise einen Jira-Fehler unter jira.codehaus.org/browse/JACKSON melden .
— StaxMan

Mir ist klar, dass diese Frage schon vor einiger Zeit gestellt wurde, aber zum späteren Nachschlagen ist objectMapper.getSerializationConfig (). SetDateFormat (df) jetzt veraltet. objectMapper.setDateFormat (df) wird jetzt vorgeschlagen.
— Patrick

Antworten:


146

Dies ist mit Jackson 2.0 und dem Joda-Modul sehr einfach geworden.

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

Maven-Abhängigkeit:

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

Code und Dokumentation: https://github.com/FasterXML/jackson-datatype-joda

Binärdateien: http://repo1.maven.org/maven2/com/fasterxml/jackson/datatype/jackson-datatype-joda/


13
Könnten Sie das bitte näher erläutern? Wohin geht dieser Code und wie wird die ObjectMapper-Instanz verwendet?
— Paul

Sie sollten spezielle Fragen zur Verwendung von Jacksons API und Maven stellen. Wohin der Code geht, hängt davon ab, ob Sie Frameworks verwenden / wie Sie Ihre Anwendung booten.
— Kimble

4
Wenn ich hinzufüge, dass ich den Kompilierungsfehler "Inkompatible Typen: JodaModule kann nicht in Modul konvertiert werden" erhalte, erwartet die Methode ein org.codehaus.jackson.map.Module, aber JodaModule hat dies nicht in seiner Hierarchie. Wie könnte dies funktionieren?
— Martin Charlesworth

4
Vielversprechend, aber derzeit fast nutzlos, da wir das zu analysierende Datumsformat nicht angeben können :(
— Vincent Mimoun-Prat

10
Sie müssen die Serialisierung als Zeitstempel deaktivieren. ObjectMapper.disable (SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
— MarekM

74

In dem Objekt, das Sie zuordnen:

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

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

4
Wie registriere ich CustomDateSerializer im Frühjahr mvc 3?
— digz6666

1
Ich weiß nichts über Spring MVC3, aber Sie können dem Jackson-Mapper-Objekt einen benutzerdefinierten Serializer hinzufügen. Siehe diesen Eintrag in Jackson. Sie müssen ein einfaches Modul für dieses SimpleModule erstellen. IsoDateTimeModule = new SimpleModule ("ISODateTimeModule", neue Version (1, 0, 0, null)); isoDateTimeModule.addSerializer (neuer JsonISODateTimeFormatSerializer ()); mapper.registerModule (isoDateTimeModule);
— Guillaume Belrose

1
@ digz6666 siehe meine Antwort hier für Spring MVC 3: stackoverflow.com/questions/7854030/…
— Aram Kocharyan

Hinweis - Stellen Sie sicher, dass Sie die oben genannten Klassen von org.codehaus.jacksonanstelle von verwenden com.fasterxml.jackson.core. Die Verwendung des zweiten Pakets hat bei mir nicht funktioniert. Tatsächlich hat meine Jersey-App die @JsonSerializedAnmerkung nicht einmal respektiert .
— Kevin Meredith

Die Antwort hat bei mir funktioniert. Diese Anmerkung würde jedoch für alle Felder erforderlich sein. Gibt es dafür eine globale Konfiguration, die mit Jackson funktioniert?
— Taher

26

Wie @Kimble bereits sagte, ist die Verwendung der Standardformatierung mit Jackson 2 sehr einfach. Registrieren JodaModuleSie sich einfach auf Ihrem ObjectMapper.

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

Für die benutzerdefinierte Serialisierung / De-Serialisierung von DateTimemüssen Sie Ihre eigenen implementieren StdScalarSerializerund StdScalarDeserializer; es ist ziemlich verworren, aber trotzdem.

Hier ist beispielsweise ein DateTimeSerializer, der ISODateFormatdie Zeitzone UTC verwendet:

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

Und der entsprechende De-Serializer:

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

Binden Sie diese dann mit einem Modul zusammen:

public class DateTimeModule extends SimpleModule {

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

Dann registrieren Sie das Modul auf Ihrem ObjectMapper:

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

Das deserilazierte DatatIme-Objekt befindet sich in der UTC-Zeitzone oder in der Zeitzone des Browsers. Bitte helfen Sie mir
— user3354457

Registriert dies den Mapper (und die Module) global?
— Raffian

16

Die einfache Lösung

Ich bin auf ein ähnliches Problem gestoßen und meine Lösung ist viel klarer als oben.

Ich habe das Muster einfach in @JsonFormat Anmerkungen verwendet

Grundsätzlich hat meine Klasse ein DateTimeFeld, also setze ich eine Anmerkung um den Getter:

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

Ich serialisiere die Klasse mit 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);
    }

Wir verwenden Jackson 2.5.4


15

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

Obwohl Sie für jedes Datumsfeld eine Anmerkung einfügen können, ist es besser, eine globale Konfiguration für Ihren Objekt-Mapper vorzunehmen. Wenn Sie Jackson verwenden, können Sie Ihre Feder wie folgt konfigurieren:

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

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

Für 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)"));
    }
}

Natürlich kann SimpleDateFormat jedes Format verwenden, das Sie benötigen.


4
setDateFormat(new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ssz"));habe den Trick für mich gemacht, thx
— Konsumierer

8

Währenddessen registriert Jackson das Joda-Modul automatisch, wenn sich das JodaModule im Klassenpfad befindet. Ich habe gerade jackson-datatype-joda zu Maven hinzugefügt und es hat sofort funktioniert.

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

JSON-Ausgabe:

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

6

Für diejenigen mit Spring Boot müssen Sie das Modul zu Ihrem Kontext hinzufügen und es wird wie folgt zu Ihrer Konfiguration hinzugefügt.

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

Und wenn Sie das neue Java8-Zeitmodul jsr-310 verwenden möchten.

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

3

Es scheint, dass es für Jackson 1.9.12 standardmäßig keine solche Möglichkeit gibt, weil:

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

Diese Klasse serialisiert Daten mit der toString () -Methode von Joda DateTime.

Der von Rusty Kuntz vorgeschlagene Ansatz funktioniert perfekt für meinen Fall.


Sie können weiterhin benutzerdefinierte Serializer und Deserializer registrieren. Diese haben Vorrang vor der Standardimplementierung.
— StaxMan

2

Ich benutze Java 8 und das hat bei mir funktioniert.

Fügen Sie die Abhängigkeit von hinzu pom.xml

<dependency>
    <groupId>com.fasterxml.jackson.datatype</groupId>
    <artifactId>jackson-datatype-jsr310</artifactId>
    <version>2.4.0</version>
</dependency>

und füge JodaModule zu deinem hinzu ObjectMapper

ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new JodaModule());
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.