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!

Haywood Jablomey
quelle
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/

Kimble
quelle
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));
    }
}
Rusty Kuntz
quelle
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());
oggmonster
quelle
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

Atais
quelle
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.

Moesio
quelle
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"}
Stephan
quelle
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();
}
jgeerts
quelle
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.

ydrozhdzhal
quelle
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());
Luciana Campello
quelle