JPA – Convertir tipos de dato Boolean y LocalTime entre la base de datos y la aplicación (incluye serialización a JSON con Jackson)

agosto 29, 2016

Supongamos que tenemos una entidad simple como la siguiente

@Entity
public class VideoTag {

    @Id
    String id;

    @Column(name = "TITULO")
    String titulo;

    @Column(name = "TIMESTAMP")
    LocalTime timestamp;

    @Column(name = "PRIVADA")
    Boolean privada;

... constructor, getters, setters, etc

Si guardamos un objeto de esta clase en la base de datos, los campos Boolean y LocalTime serán persistidos como [‘true, ‘false’] o ‘{hour: 10, minute:0, seconds: 0}’, respectivamente.

Esto puede ser aceptable, pero hay ocasiones que necesitamos representar esos tipos de datos de forma diferente en la base de datos, por ejemplo, si hay un sistema existente que guarda ‘S’ o ‘N’ para los valores booleanos o una cadena como ’10:20:00′ para representar un objeto LocalTime.

En estos casos es necesario utilizar un ‘Convertidor’ para traducir entre la base de datos y nuestra aplicación. Por ejemplo,

@Converter
public class BooleanToStringConverter implements AttributeConverter<Boolean, String>{

    @Override
    public String convertToDatabaseColumn(Boolean value) {
        return (value != null && value) ? "S" : "N";
    }

    @Override
    public Boolean convertToEntityAttribute(String value) {
        return "S".equals(value) ? true : false;
    }

}

y para la clase LocalTime

@Converter
public class LocalTimeToStringConverter implements AttributeConverter<LocalTime, String>{

    @Override
    public String convertToDatabaseColumn(LocalTime value) {
        return value.toString();
    }

    @Override
    public LocalTime convertToEntityAttribute(String value) {
        return LocalTime.parse(value);
    }

}

Con ello ya podemos guardar y leer de la base de datos en el formato esperado, solo basta especificar en nuestra entidad que vamos a utilizar estos Convertidores

    @Column(name = "TIMESTAMP")
    @Convert(converter = LocalTimeToStringConverter.class)
    LocalTime timestamp;

    @Column(name = "PRIVADA")
    @Convert(converter = BooleanToStringConverter.class)
    Boolean privada;

Si utilizaste un archivo persistence.xml para escpecificar las entidades, también debes agregar los convertidores

...
<!--    Convertidores-->
    <class>mx.gob.queretaro.brujula.tsj.domain.jpa.BooleanToStringConverter</class>
    <class>mx.gob.queretaro.brujula.tsj.domain.jpa.LocalTimeToStringConverter</class>
...

Genial! pero cuando intentamos enviar uno de estos objetos a través de un servicio REST como JSON -utilizando Jackson-, sigue utilizando el formato anterior, crap!

Bueno, pues también tenemos que especificar la forma en que vamos a serializar los datos con Jackson. Para ello, necesitamos implementar 2 interfaces JsonSerializer y JsonDeserializer

/**
 * Convierte un objeto LocalTime y lo convierte a una representacion serializable de tipo cadena
 * p. ej. "10:15:30" o "13:45.30.123456789"
 */
public class LocalTimeSerializer extends JsonSerializer<LocalTime>{

    @Override
    public void serialize(LocalTime t, JsonGenerator jg, SerializerProvider sp) throws IOException, JsonProcessingException {
        jg.writeString(t.toString());
    }

}
/**
 * Convierte una cadena a un objeto LocalTime
 */
public class LocalTimeDeserializer extends JsonDeserializer<LocalTime>{

    @Override
    public LocalTime deserialize(JsonParser jp, DeserializationContext dc) throws IOException, JsonProcessingException {
        return LocalTime.parse(jp.getText());
    }

}

Y finalmente las agregamos a la entidad

@Column(name = "TIMESTAMP")
    @Convert(converter = LocalTimeToStringConverter.class)
    @JsonSerialize(using = LocalTimeSerializer.class)
    @JsonDeserialize(using = LocalTimeDeserializer.class)
    LocalTime timestamp;

Fuentes:
http://stackoverflow.com/questions/1154833/configure-hibernate-using-jpa-to-store-y-n-for-type-boolean-instead-of-0-1
http://stackoverflow.com/questions/27952472/serialize-deserialize-java-8-java-time-with-jackson-json-mapper
http://stackoverflow.com/questions/27574855/registering-converters-in-jpa-2-1-with-eclipselink

Anuncios

Responder

Introduce tus datos o haz clic en un icono para iniciar sesión:

Logo de WordPress.com

Estás comentando usando tu cuenta de WordPress.com. Cerrar sesión / Cambiar )

Imagen de Twitter

Estás comentando usando tu cuenta de Twitter. Cerrar sesión / Cambiar )

Foto de Facebook

Estás comentando usando tu cuenta de Facebook. Cerrar sesión / Cambiar )

Google+ photo

Estás comentando usando tu cuenta de Google+. Cerrar sesión / Cambiar )

Conectando a %s

A %d blogueros les gusta esto: