Search code examples
grailsgrails-orm

Adapt field to store to database


Say I have a field content that is a json. I would like to store it in database so that my domain class keeps only the 1 field only. (It's more of a brain task ;-)

class MyDomain{

   def content

   static constraints = {
        content nullable: false, blank: false, sqlType: "text" // adapter from JSON to String??
    }

def beforeInsert(){
    content = content.toString()
}

def beforeUpdate(){
    content = content.toString()
}

def afterInsert(){
    content = JSON.parse(content) as JSON
}

def afterUpdate(){
    content = JSON.parse(content) as JSON
}

def onLoad(){
    content = JSON.parse(content) as JSON
}

}

I want my domain object to expose only content so I don't want to use another field like String contentAsText because it would be visible outside.

In the whole GORM documentation I haven't found a thing how to manage it. I've tried beforeValidate()/beforeInsert() and onLoad() methods but no luck...

How can I adapt the value before it gets persisted?


Solution

  • You can define a custom hibernate user-type for JSONElement as described here: https://stackoverflow.com/a/28655708/607038

    In domain class constraints:

    static constraints = {
       content type: JSONObjectUserType
    }
    

    User Type Class:

    import org.grails.web.json.JSONObject
    import org.hibernate.HibernateException
    import org.hibernate.engine.spi.SessionImplementor
    import org.hibernate.type.StandardBasicTypes
    import org.hibernate.usertype.EnhancedUserType
    
    import java.sql.PreparedStatement
    import java.sql.ResultSet
    import java.sql.SQLException
    import java.sql.Types
    
    class JSONObjectUserType implements EnhancedUserType, Serializable {
    
        private static final int[] SQL_TYPES = [Types.VARCHAR]
    
        @Override
        public int[] sqlTypes() {
            return SQL_TYPES
        }
    
        @Override
        public Class returnedClass() {
            return JSONObject.class
        }
    
        @Override
        public boolean equals(Object x, Object y) throws HibernateException {
            if (x == y) {
                return true
            }
            if (x == null || y == null) {
                return false
            }
            JSONObject zx = (JSONObject) x
            JSONObject zy = (JSONObject) y
            return zx.equals(zy)
        }
    
        @Override
        public int hashCode(Object object) throws HibernateException {
            return object.hashCode()
        }
    
        @Override
        public Object nullSafeGet(ResultSet resultSet, String[] names, SessionImplementor session, Object owner)
            throws HibernateException, SQLException {
            Object jsonObject = StandardBasicTypes.STRING.nullSafeGet(resultSet, names, session, owner)
            if (jsonObject == null) {
                return null
            }
            return new JSONObject((String) jsonObject)
        }
    
        @Override
        public void nullSafeSet(PreparedStatement preparedStatement, Object value, int index, SessionImplementor session)
            throws HibernateException, SQLException {
            if (value == null) {
                StandardBasicTypes.STRING.nullSafeSet(preparedStatement, null, index, session)
            } else {
                JSONObject jsonObject = (JSONObject) value
                StandardBasicTypes.STRING.nullSafeSet(preparedStatement, jsonObject.toString(), index, session)
            }
        }
    
        @Override
        public Object deepCopy(Object value) throws HibernateException {
            return value
        }
    
        @Override
        public boolean isMutable() {
            return false
        }
    
        @Override
        public Serializable disassemble(Object value) throws HibernateException {
            return (Serializable) value
        }
    
        @Override
        public Object assemble(Serializable cached, Object value) throws HibernateException {
            return cached
        }
    
        @Override
        public Object replace(Object original, Object target, Object owner) throws HibernateException {
            return original
        }
    
        @Override
        public String objectToSQLString(Object object) {
            throw new UnsupportedOperationException()
        }
    
        @Override
        public String toXMLString(Object object) {
            return object.toString()
        }
    
        @Override
        public Object fromXMLString(String string) {
            return new JSONObject(string)
        }
    }