In one of my project, I wanted to store the value of a domain object field as json string in database. Below is an example how it can be done.
Hibernate json user type
import com.fasterxml.jackson.annotation.JsonInclude import com.fasterxml.jackson.databind.JavaType import com.fasterxml.jackson.databind.ObjectMapper import com.fasterxml.jackson.databind.type.SimpleType import groovy.transform.CompileStatic import org.hibernate.engine.spi.SessionImplementor import org.hibernate.usertype.ParameterizedType import org.hibernate.usertype.UserType import java.sql.PreparedStatement import java.sql.ResultSet import java.sql.SQLException import java.sql.Types @CompileStatic class JsonUserType implements UserType, ParameterizedType { private static final int[] SQL_TYPES = [Types.LONGVARCHAR] as int[] private Class<?> returnedClass; @Override public boolean equals(Object x, Object y) throws HibernateException { if (x == y) { return true; } else if (x == null || y == null) { return false; } else { return x.equals(y); } } @Override public int hashCode(Object x) throws HibernateException { return null == x ? 0 : x.hashCode(); } @Override public boolean isMutable() { return true; } @Override public void nullSafeSet(PreparedStatement st, Object value, int index, SessionImplementor session) throws HibernateException, SQLException { if(value == null) { st.setNull(index, Types.VARCHAR) } else { String s = convertObjectToJson(value) st.setString(index, s) } } @Override public Object nullSafeGet(ResultSet rs, String[] names, SessionImplementor session, Object owner) throws HibernateException, SQLException { String value = rs.getString(names[0]) def result = null if (value != null && !value.equals("")) { try { result = convertJsonToObject(value) } catch (IOException e) { throw new HibernateException("Exception deserializing value " + value, e); } } return result; } Object convertJsonToObject(String content) { if ((content == null) || (content.isEmpty())) { return null; } try { ObjectMapper mapper = new ObjectMapper() mapper.enableDefaultTyping() JavaType type = createJavaType(mapper) if (type == null) return mapper.readValue(content, returnedClass); return mapper.readValue(content, type); } catch (IOException e) { throw new RuntimeException(e); } } String convertObjectToJson(Object object) { try { ObjectMapper mapper = new ObjectMapper() mapper.enableDefaultTyping() mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); return mapper.writeValueAsString(object); } catch (IOException e) { throw new RuntimeException(e); } } @Override public Object deepCopy(Object value) throws HibernateException { String json = convertObjectToJson(value); return convertJsonToObject(json); } @Override public Object replace(Object original, Object target, Object owner) throws HibernateException { return deepCopy(original); } @Override public Serializable disassemble(Object value) throws HibernateException { return (Serializable) deepCopy(value); } @Override public Object assemble(Serializable cached, Object owner) throws HibernateException { return deepCopy(cached); } public JavaType createJavaType(ObjectMapper mapper) { try { return SimpleType.construct(returnedClass()); } catch (IllegalArgumentException e) { return null; } } @Override public int[] sqlTypes() { return SQL_TYPES; } @Override public void setParameterValues(Properties parameters) { this.returnedClass = Class.forName(parameters.getProperty('clazz')) } @Override public Class<?> returnedClass() { return this.returnedClass; } }Gorm mapping for the json user type
Page { PageBody body static mapping = { body type: JsonUserType, params: [clazz: PageBody.name] } static constraints = { body nullable: true } }Storing a list type field as json
class BlogPage extends Page { List<Region> regions static mapping = { regions type: JsonUserType, params: [clazz: ArrayList.name] } static constraints = { regions nullable: true } }This is a quick and dirty implementation. There's scope to improve it further. eg. You can modify it to take the advantage of database system's native json column type if your database supports it.