Nunca pude hacer que esto funcionara de manera simple usando anotaciones. Para conseguir que funcione, he creado una ContextResolver
para ObjectMapper
, a continuación, he añadido el JSR310Module
( actualización: ahora es JavaTimeModule
su lugar ), junto con una advertencia más, lo cual era la necesidad de fijar la fecha de escritura-como-marca de tiempo en false. Vea más en la documentación para el módulo JSR310 . Aquí hay un ejemplo de lo que usé.
Dependencia
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
<version>2.4.0</version>
</dependency>
Nota: Un problema que enfrenté con esto es que la jackson-annotation
versión extraída por otra dependencia, utilizó la versión 2.3.2, que canceló la 2.4 requerida por el jsr310
. Lo que sucedió fue que obtuve un NoClassDefFound para ObjectIdResolver
, que es una clase 2.4. Así que solo necesitaba alinear las versiones de dependencia incluidas
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;
}
}
Clase de recursos
@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;
}
}
Prueba
curl -v http://localhost:8080/api/person
Resultado: {"birthDate":"2015-03-01"}
curl -v -POST -H "Content-Type:application/json" -d "{\"birthDate\":\"2015-03-01\"}" http://localhost:8080/api/person
Resultado: 2015-03-01
Consulte también aquí la solución JAXB.
ACTUALIZAR
El JSR310Module
está en desuso a partir de la versión 2.7 de Jackson. En su lugar, debe registrar el módulo JavaTimeModule
. Sigue siendo la misma dependencia.
getContext
método. Si se llama a este método, no veo una razón para que esto no funcione. Si no se llama, entonces puede ser algo que debe arreglarse con la configuración de la aplicación. Para eso necesitaría ver más de lo que me ha proporcionado. Al igual que la versión Resteasy, las dependencias, la configuración de la aplicación, ya sea web.xml o la subclase de aplicación. Básicamente suficiente para reproducir el problemaObjectMapper
como lo hace swagger (puede ver un enlace en la pregunta). No sé, ya que no trabajo mucho con la arrogancia. Pero creo que la arrogancia es el problema principal, por qué no se llama a la resolución de contexto.@JsonSerialize y @JsonDeserialize funcionaron bien para mí. Eliminan la necesidad de importar el módulo jsr310 adicional:
Deserializador:
Serializador:
fuente
jackson-datatype-jsr310
. No es necesario definirlos manualmente en su proyecto.jackson-datatype-jsr310
.funciona bien para mi
fuente
new com.fasterxml.jackson.datatype.jsr310.JSR310Module()
para la versión 2.5.4 de Jackson. La clase JavaTimeModule no existe en esta versión.LocalDateTime
(jackson 2.9.5). Se requiere 1 dependencia adicional, por lo que mi build.sbt se parece a:"com.fasterxml.jackson.module" %% "jackson-module-scala" % "2.9.5", "com.fasterxml.jackson.datatype" % "jackson-datatype-jsr310" % "2.9.5"
En la aplicación web Spring Boot, con Jackson y JSR 310 versión "2.8.5"
Los
@JsonFormat
trabajos:fuente
@JsonDeserialize(using= LocalDateDeserializer.class)
@JsonFormat
solo por cambiar el formato de datos de salida. stackoverflow.com/a/53251526/816759 funciona perfecto con@JsonFormat
,@JsonDeserialize
,@JsonSerialize
spring.jackson.serialization.write-dates-as-timestamps=false
a suapplication.properties
, y lo formateayyyy-MM-dd
automáticamente. No es necesario@JsonFormat
La solución más simple (que también admite la deserialización y la serialización) es
Mientras usa las siguientes dependencias en su proyecto.
Maven
Gradle
No se requiere una implementación adicional de ContextResolver, Serializer o Deserializer.
fuente
ObjectMapper
que no se hayaJavaTimeModule
registrado. Si su instancia de ObjectMapper se proporciona desde el framework spring / MessageConverter. Hicieron algo de magia para conectarlos. En otro caso, deberegisterModule
habilitarLocalDateDeserializer
por defecto para todos los "LocalDate" en POJOYa que
LocalDateSerializer
convierte en "[año, mes, día]" (una matriz json) en lugar de "año-mes-día" (una cadena json) de forma predeterminada, y dado que no quiero requerir ningunaObjectMapper
configuración especial (puede hacerLocalDateSerializer
generar cadenas si lo deshabilitaSerializationFeature.WRITE_DATES_AS_TIMESTAMPS
pero eso requiere una configuración adicionalObjectMapper
), utilizo lo siguiente:importaciones:
código:
Y ahora solo puedo usar
new ObjectMapper()
para leer y escribir mis objetos sin ninguna configuración especial.fuente
"2018-12-07"
lugar de"2018-12-7"
eso obtendrás un error.yyyy-MM-dd
formato (2 dígitos mes y día), no formatoyyyy-M-d
(1 dígito mes o día).Solo una actualización de la respuesta de Christopher.
Desde la versión 2.6.0
Utilice JavaTimeModule en lugar de JSR310Module (en desuso).
De acuerdo con la documentación , el nuevo JavaTimeModule usa la misma configuración estándar para la serialización predeterminada que NO usa Id. De zona horaria, y en su lugar solo utiliza compensaciones de zona horaria compatibles con ISO-8601.
El comportamiento se puede cambiar usando SerializationFeature.WRITE_DATES_WITH_ZONE_ID
fuente
MAPPER.registerModule(new JavaTimeModule());
línea. Me permitió formatear objetos LocalDate como formato "2020-02-20". No necesitaba laMAPPER.configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false);
línea, para lo que estaba buscandoLa siguiente anotación funcionó bien para mí.
No se necesitan dependencias adicionales.
fuente
fuente
https://stackoverflow.com/a/53251526/1282532 es la forma más simple de serializar / deserializar la propiedad. Tengo dos preocupaciones con respecto a este enfoque: hasta cierto punto, violación del principio DRY y alto acoplamiento entre pojo y mapper.
En caso de que tenga POJO con múltiples campos LocalDate, es mejor configurar el mapeador en lugar de POJO. Puede ser tan simple como https://stackoverflow.com/a/35062824/1282532 si está utilizando valores ISO-8601 ("2019-01-31")
En caso de que necesite manejar un formato personalizado, el código será así:
La lógica se escribe solo una vez, se puede reutilizar para múltiples POJO
fuente
Más simple y más corto hasta ahora:
no se requiere dependencia con Spring boot> = 2.2+
fuente
A partir de 2020 y Jackson 2.10.1 no hay necesidad de ningún código especial, solo es cuestión de decirle a Jackson lo que quieres:
Esto ya se ha mencionado en esta respuesta , estoy agregando una prueba unitaria para verificar la funcionalidad:
TestBean usa Lombok para generar el repetitivo para el bean.
fuente
En la clase de configuración, defina las clases LocalDateSerializer y LocalDateDeserializer y regístrelas en ObjectMapper a través de JavaTimeModule como se muestra a continuación:
fuente
Si su solicitud contiene un objeto como este:
Entonces puedes usar:
Sobre el campo:
El código está en Kotlin, pero esto también funcionaría para Java, por supuesto.
fuente