webentwicklung-frage-antwort-db.com.de

Java 8 LocalDate Jackson Format

Für Java.util.Date wenn ich es tue

@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "dd/MM/yyyy")  
  private Date dateOfBirth;

dann in JSON-Anfrage, wenn ich sende

{ {"dateOfBirth":"01/01/2000"} }  

es klappt.

Wie soll ich das für Java 8's LocalDate Feld machen ??

Ich habe versucht zu haben

@JsonDeserialize(using = LocalDateDeserializer.class)  
@JsonSerialize(using = LocalDateSerializer.class)  
private LocalDate dateOfBirth;  

Es hat nicht funktioniert.

Kann mir jemand bitte mitteilen, wie ich das richtig mache ..

Nachfolgend sind Abhängigkeiten aufgeführt

<dependency>
         <groupId>org.jboss.resteasy</groupId>
         <artifactId>jaxrs-api</artifactId>
         <version>3.0.9.Final</version>
      </dependency>
      <dependency>
         <groupId>com.fasterxml.jackson.jaxrs</groupId>
         <artifactId>jackson-jaxrs-json-provider</artifactId>
         <version>2.4.2</version>
      </dependency>
      <dependency>
         <groupId>com.wordnik</groupId>
         <artifactId>swagger-annotations</artifactId>
         <version>1.3.10</version>
      </dependency>
      <dependency>
101
JAB

Ich war nie in der Lage, dies mithilfe von Anmerkungen einfach umzusetzen. Damit es funktioniert, habe ich ein ContextResolver für ObjectMapper erstellt und dann das JSR310Module, zusammen mit einer weiteren Einschränkung, bei der Schreibdatum als Zeitstempel auf falsch gesetzt werden musste. Weitere Informationen finden Sie unter Dokumentation zum JSR310-Modul . Hier ist ein Beispiel von dem, was ich verwendet habe.

Abhängigkeit

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

Hinweis: Ein Problem, mit dem ich konfrontiert war, war, dass die jackson-annotation Version, die von einer anderen Abhängigkeit gezogen wurde, verwendete Version 2.3.2, die die 2.4, die von der jsr310. Was passiert ist, war, dass ich ein NoClassDefFound für ObjectIdResolver bekommen habe, das ist eine 2.4 Klasse. Also musste ich nur die enthaltenen Abhängigkeitsversionen ausrichten

ContextResolver

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jsr310.JSR310Module;
import javax.ws.rs.ext.ContextResolver;
import javax.ws.rs.ext.Provider;

@Provider
public class ObjectMapperContextResolver implements ContextResolver<ObjectMapper> {  
    private final ObjectMapper MAPPER;

    public ObjectMapperContextResolver() {
        MAPPER = new ObjectMapper();
        // Now you should use JavaTimeModule instead
        MAPPER.registerModule(new JSR310Module());
        MAPPER.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
    }

    @Override
    public ObjectMapper getContext(Class<?> type) {
        return MAPPER;
    }  
}

Ressourcenklasse

@Path("person")
public class LocalDateResource {

    @GET
    @Produces(MediaType.APPLICATION_JSON)
    public Response getPerson() {
        Person person = new Person();
        person.birthDate = LocalDate.now();
        return Response.ok(person).build();
    }

    @POST
    @Consumes(MediaType.APPLICATION_JSON)
    public Response createPerson(Person person) {
        return Response.ok(
                DateTimeFormatter.ISO_DATE.format(person.birthDate)).build();
    }

    public static class Person {
        public LocalDate birthDate;
    }
}

Prüfung

curl -v http://localhost:8080/api/person
Ergebnis: {"birthDate":"2015-03-01"}

curl -v -POST -H "Content-Type:application/json" -d "{\"birthDate\":\"2015-03-01\"}" http://localhost:8080/api/person
Ergebnis: 2015-03-01


Siehe auch hier für die JAXB-Lösung.

AKTUALISIEREN

Das JSR310Module ist seit Version 2.7 von Jackson veraltet. Stattdessen sollten Sie das Modul JavaTimeModule registrieren. Es ist immer noch die gleiche Abhängigkeit.

85
Paul Samsotha

@JsonSerialize und @JsonDeserialize funktionierten gut für mich. Sie machen den Import des zusätzlichen Moduls jsr310 überflüssig:

@JsonDeserialize(using = LocalDateDeserializer.class)  
@JsonSerialize(using = LocalDateSerializer.class)  
private LocalDate dateOfBirth;

Deserializer:

public class LocalDateDeserializer extends StdDeserializer<LocalDate> {

    private static final long serialVersionUID = 1L;

    protected LocalDateDeserializer() {
        super(LocalDate.class);
    }


    @Override
    public LocalDate deserialize(JsonParser jp, DeserializationContext ctxt)
            throws IOException, JsonProcessingException {
        return LocalDate.parse(jp.readValueAs(String.class));
    }

}

Serializer:

public class LocalDateSerializer extends StdSerializer<LocalDate> {

    private static final long serialVersionUID = 1L;

    public LocalDateSerializer(){
        super(LocalDate.class);
    }

    @Override
    public void serialize(LocalDate value, JsonGenerator gen, SerializerProvider sp) throws IOException, JsonProcessingException {
        gen.writeString(value.format(DateTimeFormatter.ISO_LOCAL_DATE));
    }
}
73
        ObjectMapper mapper = new ObjectMapper();
        mapper.registerModule(new JavaTimeModule());
        mapper.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);

funktioniert gut für mich.

45
欧阳世雄

Im Frühling Boot Web App, mit 'jackson' und 'jsr310' Version "2.8.5"

compile "com.fasterxml.jackson.core:jackson-databind:2.8.5"
runtime "com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.8.5"

Das '@JsonFormat' funktioniert:

import com.fasterxml.jackson.annotation.JsonFormat;

@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "yyyy-MM-dd")
private LocalDate birthDate;
37

Die einfachste Lösung (die auch Deserialisierung und Serialisierung unterstützt) ist

import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;

@JsonFormat(shape = JsonFormat.Shape.STRING, pattern = "dd/MM/yyyy")
@JsonDeserialize(using = LocalDateDeserializer.class)
@JsonSerialize(using = LocalDateSerializer.class)
private LocalDate dateOfBirth;

Während Sie die folgenden Abhängigkeiten in Ihrem Projekt verwenden.

Maven

<dependency>
   <groupId>com.fasterxml.jackson.core</groupId>
   <artifactId>jackson-databind</artifactId>
   <version>2.9.7</version>
</dependency>
<dependency>
   <groupId>com.fasterxml.jackson.datatype</groupId>
   <artifactId>jackson-datatype-jsr310</artifactId>
   <version>2.9.7</version>
</dependency>

Gradle

compile "com.fasterxml.jackson.core:jackson-databind:2.9.7"
compile "com.fasterxml.jackson.datatype:jackson-datatype-jsr310:2.9.7"

Es ist keine zusätzliche Implementierung eines ContextResolvers, Serializers oder Deserializers erforderlich.

17
Paul Wasilewski

Da LocalDateSerializer es in "[year, month, day]" (ein JSON-Array) anstatt "year-month-day" (eine JSON-Zeichenfolge) umwandelt, und da ich nicht verlangen möchte Bei jeder speziellen ObjectMapper Einrichtung (Sie können LocalDateSerializer Zeichenfolgen generieren lassen, wenn Sie SerializationFeature.WRITE_DATES_AS_TIMESTAMPS deaktivieren, dies erfordert jedoch eine zusätzliche Einrichtung für ObjectMapper) verwende ich Folgendes:

importe:

import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;

code:

// generates "yyyy-MM-dd" output
@JsonSerialize(using = ToStringSerializer.class)
// handles "yyyy-MM-dd" input just fine (note: "yyyy-M-d" format will not work)
@JsonDeserialize(using = LocalDateDeserializer.class)
private LocalDate localDate;

Und jetzt kann ich einfach new ObjectMapper() verwenden, um meine Objekte ohne spezielle Einrichtung zu lesen und zu schreiben.

15
Shadow Man

Nur ein Update von Christopher Antwort.

Seit der Version 2.6.0

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

Verwenden Sie das JavaTimeModule anstelle von JSR310Module (veraltet).

@Provider
public class ObjectMapperContextResolver implements ContextResolver<ObjectMapper> {  
    private final ObjectMapper MAPPER;

    public ObjectMapperContextResolver() {
        MAPPER = new ObjectMapper();
        MAPPER.registerModule(new JavaTimeModule());
        MAPPER.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
    }

    @Override
    public ObjectMapper getContext(Class<?> type) {
        return MAPPER;
    }  
}

Laut Dokumentation verwendet das neue JavaTimeModule standardmäßig dieselben Standardeinstellungen für die Serialisierung, die KEINE Zeitzonen-IDs verwenden, und verwendet stattdessen nur ISO-8601-kompatible Zeitzonen-Offsets.

Das Verhalten kann mithilfe von SerializationFeature.WRITE_DATES_WITH_ZONE_ID geändert werden.

4
bdzzaid

https://stackoverflow.com/a/53251526/1282532 ist die einfachste Methode zum Serialisieren/Deserialisieren von Eigenschaften. Ich habe zwei Bedenken in Bezug auf diesen Ansatz - bis zu einem gewissen Punkt Verstoß gegen das DRY Prinzip und hohe Kopplung zwischen Pojo und Mapper.

public class Trade {
    @JsonFormat(pattern = "yyyyMMdd")
    @JsonDeserialize(using = LocalDateDeserializer.class)
    @JsonSerialize(using = LocalDateSerializer.class)
    private LocalDate tradeDate;
    @JsonFormat(pattern = "yyyyMMdd")
    @JsonDeserialize(using = LocalDateDeserializer.class)
    @JsonSerialize(using = LocalDateSerializer.class)
    private LocalDate maturityDate;
    @JsonFormat(pattern = "yyyyMMdd")
    @JsonDeserialize(using = LocalDateDeserializer.class)
    @JsonSerialize(using = LocalDateSerializer.class)
    private LocalDate entryDate;
}

Wenn Sie POJO mit mehreren LocalDate-Feldern haben, ist es besser, Mapper anstelle von POJO zu konfigurieren. Dies kann so einfach sein wie https://stackoverflow.com/a/35062824/1282532 wenn Sie ISO-8601-Werte verwenden ("2019-01-31")

Falls Sie ein benutzerdefiniertes Format benötigen, sieht der Code folgendermaßen aus:

ObjectMapper mapper = new ObjectMapper();
JavaTimeModule javaTimeModule = new JavaTimeModule();
javaTimeModule.addDeserializer(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ofPattern("yyyyMMdd")));
javaTimeModule.addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ofPattern("yyyyMMdd")));
mapper.registerModule(javaTimeModule);

Die Logik wird nur einmal geschrieben und kann für mehrere POJOs wiederverwendet werden

1
Pavel

Definieren Sie in der Konfigurationsklasse LocalDateSerializer und LocalDateDeserializer und registrieren Sie diese in ObjectMapper über JavaTimeModule wie folgt:

@Configuration
public class AppConfig
{
@Bean
    public ObjectMapper objectMapper()
    {
        ObjectMapper mapper = new ObjectMapper();
        mapper.setSerializationInclusion(Include.NON_EMPTY);
        //other mapper configs
        // Customize de-serialization


        JavaTimeModule javaTimeModule = new JavaTimeModule();
        javaTimeModule.addSerializer(LocalDate.class, new LocalDateSerializer());
        javaTimeModule.addDeserializer(LocalDate.class, new LocalDateDeserializer());
        mapper.registerModule(javaTimeModule);

        return mapper;
    }

    public class LocalDateSerializer extends JsonSerializer<LocalDate> {
        @Override
        public void serialize(LocalDate value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
            gen.writeString(value.format(Constant.DATE_TIME_FORMATTER));
        }
    }

    public class LocalDateDeserializer extends JsonDeserializer<LocalDate> {

        @Override
        public LocalDate deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
            return LocalDate.parse(p.getValueAsString(), Constant.DATE_TIME_FORMATTER);
        }
    }
}
0
nanosoft