Jackson 2.x Formatear fechas (Date, LocalDate, etc.)
En el tutorial anterior aprendimos como usar la clase ObjectMapper
de la librería Jackson 2.x para leer y escribir archivos o cadenas de texto en formato JSON, en esta publicación nos centraremos en el trabajo con las clases usadas por Java para representar fechas, como: Date
, LocalDate
, DateTime
, etc., ya sea usando la API Java 8 o Joda Time.
Primero veamos qué pasa cuando deseamos convertir un objeto java.util.Date
a formato JSON, el código es el siguiente:
Date fecha = new Date();
ObjectMapper mapper = new ObjectMapper();
String out = mapper.writeValueAsString(fecha);
System.out.println("Hoy es: " + out);
Este código produce la salida:
Hoy es: 1493568561678
Este número que vemos representa la fecha en milisegundos transcurridos a partir de un punto de referencia, guardar una fecha de esta manera no es un error, el ObjectMapper
puede convertir este número a la fecha adecuada, pero que pasa si deseamos guardar la fecha en un formato más legible, la primera opción es la siguiente:
Date fecha = new Date();
ObjectMapper mapper = new ObjectMapper();
mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
String out = mapper.writeValueAsString(fecha);
System.out.println("Hoy es: " + out);
La salida al deshabilitar la opción WRITE_DATES_AS_TIMESTAMPS se ve de esta manera:
Hoy es: "2017-04-30T16:18:02.341+0000"
Como vemos la cadena JSON es más legible, aun así, contiene información que nos deseamos o está en un formato que tal vez no sea de nuestro gusto, si ese es el caso podemos cambiar el formato en que Jackson 2.x serializa las fechas, esto se puede hacer de dos maneras, usando una clase apropiada para formatear o con anotaciones.
1. Formatear fechas usando la clase SimpleDateFormat
Usando la clase SimpleDateFormat
podemos indicar el patrón que se utilizara para formatear la fecha, para indicarle al ObjectMapper
que debe usar esta clase para formatear los objetos Date usaremos el método mapper.setDateFormat(sdf)
, ejemplo:
Date fecha = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("dd/MM/yy hh:mm");
ObjectMapper mapper = new ObjectMapper();
mapper.setDateFormat(sdf);
String out = mapper.writeValueAsString(fecha);
System.out.println("Hoy es: " + out);
Nuestro formato está definido por la cadena "dd/MM/yy hh:mm" y genera las siguiente salida:
Hoy es: "01/05/17 10:09"
2. Formatear fechas con la anotación @JsonFormat
Para el código de ejemplo de uso de la anotación @JsonFormat
crearemos las siguiente clase que nos ayudará a demostrar su uso.
public class Example {
private String nombre;
@JsonFormat(pattern = "dd-MM-yyyy hh:mm:ss")
private Date fecha;
public Example(String nombre, Date fecha) {
this.nombre = nombre;
this.fecha = fecha;
}
}
Al igual que el anterior el patrón está definido por la cadena "dd-MM-yyyy hh:mm:ss", no es necesario configurar algo, Jackson detectará la anotación y formateara la salida de manera correspondiente.
Example ex = new Example("carmelo", Date.from(Instant.now()));
ObjectMapper mapper = new ObjectMapper();
String out = mapper
.writerWithDefaultPrettyPrinter()
.writeValueAsString(ex);
System.out.println("Example object: " + out);
La cadena en formato JSON es la siguiente:
Example object: {
"nombre" : "carmelo",
"fecha" : "01-05-2017 04:17:33"
}
Usar Date-Time API de Java 8 en Jackson 2.x
Para utilizar la Date-Time API introducida con Java 8 debemos primero, agregar la dependencia jackson-datatype-jsr310 a nuestro proyecto, luego debemos registrar el módulo correspondiente, llamado: JSR310Module
, vemos el ejemplo.
El archivo POM requiere las siguientes dependencias:
<dependencies>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.8.8</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.datatype</groupId>
<artifactId>jackson-datatype-jsr310</artifactId>
<version>2.4.0</version>
</dependency>
</dependencies>
Registrar el módulo JSR310Module
:
LocalDate fecha = LocalDate.of(2010, Month.MARCH, 20);
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new JSR310Module());
mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
String out = mapper.writeValueAsString(fecha);
System.out.println("java.time.LocalDate: " + out);
Lo siguiente que haremos será crear un serializer personalizado para la clase LocalDate
, este nos permitirá definir como se escribe la cadena JSON a partir de un objeto LocalDate
, para crear esta clase debemos extender la clase base StdSerializer<T>
, de este modo:
public class LocalDateSerializer extends StdSerializer<LocalDate> {
private static DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd::MM::yy");
public LocalDateSerializer() {
this(LocalDate.class);
}
public LocalDateSerializer(Class<LocalDate> date) {
super(date);
}
@Override
public void serialize(LocalDate t, JsonGenerator jg, SerializerProvider sp) throws IOException {
jg.writeString(formatter.format(t));
}
}
El trabajo lo realiza el método serialize(...)
usamos el método jg.writeString(...)
para escribir el objeto LocalDate
en el formato definido por el patrón "dd::MM::yy".
Para usar el serializer debemos agregarlo al módulo.
JSR310Module module = new JSR310Module();
module.addSerializer(new LocalDateSerializer());
La clase LocalDateSerializar
se encarga de escribir el objeto a formato JSON, si deseamos realizar el proceso inverso debemos escribir otra clase, esta vez extendiendo StdDeserializer<LocalDate>
, la tarea de esta clase será tomar la cadena JSON y convertirla en un objeto LocalDate
, ejemplo:
public class LocalDateDeserializer extends StdDeserializer<LocalDate> {
private static DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd::MM::yy");
public LocalDateDeserializer() {
this(LocalDate.class);
}
public LocalDateDeserializer(Class<LocalDate> date) {
super(date);
}
@Override
public LocalDate deserialize(JsonParser jp, DeserializationContext dc) throws IOException, JsonProcessingException {
return LocalDate.parse(jp.getValueAsString(), formatter);
}
}
Veamos un ejemplo de como usar estas clases:
LocalDate fecha = LocalDate.of(2010, Month.MARCH, 20);
JSR310Module module = new JSR310Module();
module.addSerializer(new LocalDateSerializer(LocalDate.class));
module.addDeserializer(LocalDate.class, new LocalDateDeserializer());
ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(module);
mapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
String out = mapper.writeValueAsString(fecha);
LocalDate date = mapper.readValue(out, LocalDate.class);
System.out.println("json format: " + out);
System.out.println("java.time.LocalDate: " + date);
La ventana de salida mostrará lo siguiente:
json format: "20::03::10"
java.time.LocalDate: 2010-03-20
Comentarios
Publicar un comentario