Si está interesado, aquí hay algunos fragmentos de código para implementar el tipo de usuario personalizado de Hibernate. Primero amplíe el dialecto de PostgreSQL para informarle sobre el tipo json, gracias a Craig Ringer por el puntero JAVA_OBJECT:
import org.hibernate.dialect.PostgreSQL9Dialect;
import java.sql.Types;
public class JsonPostgreSQLDialect extends PostgreSQL9Dialect {
public JsonPostgreSQLDialect() {
super();
this.registerColumnType(Types.JAVA_OBJECT, "json");
}
}
A continuación, implemente org.hibernate.usertype.UserType. La siguiente implementación asigna valores de cadena al tipo de base de datos json y viceversa. Recuerde que las cadenas son inmutables en Java. También se podría utilizar una implementación más compleja para mapear beans Java personalizados a JSON almacenados en la base de datos.
package foo;
import org.hibernate.HibernateException;
import org.hibernate.engine.spi.SessionImplementor;
import org.hibernate.usertype.UserType;
import java.io.Serializable;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
public class StringJsonUserType implements UserType {
@Override
public int[] sqlTypes() {
return new int[] { Types.JAVA_OBJECT};
}
@Override
public Class returnedClass() {
return String.class;
}
@Override
public boolean equals(Object x, Object y) throws HibernateException {
if( x== null){
return y== null;
}
return x.equals( y);
}
@Override
public int hashCode(Object x) throws HibernateException {
return x.hashCode();
}
@Override
public Object nullSafeGet(ResultSet rs, String[] names, SessionImplementor session, Object owner) throws HibernateException, SQLException {
if(rs.getString(names[0]) == null){
return null;
}
return rs.getString(names[0]);
}
@Override
public void nullSafeSet(PreparedStatement st, Object value, int index, SessionImplementor session) throws HibernateException, SQLException {
if (value == null) {
st.setNull(index, Types.OTHER);
return;
}
st.setObject(index, value, Types.OTHER);
}
@Override
public Object deepCopy(Object value) throws HibernateException {
return value;
}
@Override
public boolean isMutable() {
return true;
}
@Override
public Serializable disassemble(Object value) throws HibernateException {
return (String)this.deepCopy( value);
}
@Override
public Object assemble(Serializable cached, Object owner) throws HibernateException {
return this.deepCopy( cached);
}
@Override
public Object replace(Object original, Object target, Object owner) throws HibernateException {
return original;
}
}
Ahora todo lo que queda es anotar las entidades. Pon algo como esto en la declaración de clase de la entidad:
@TypeDefs( {@TypeDef( name= "StringJsonObject", typeClass = StringJsonUserType.class)})
Luego anote la propiedad:
@Type(type = "StringJsonObject")
public String getBar() {
return bar;
}
Hibernate se encargará de crear la columna con el tipo json por usted y manejará el mapeo de un lado a otro. Inyecte bibliotecas adicionales en la implementación del tipo de usuario para un mapeo más avanzado.
Aquí hay una muestra rápida de un proyecto de GitHub si alguien quiere jugar con él:
https://github.com/timfulmer/hibernate-postgres-jsontype