Reputation: 21565
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?
Upvotes: 0
Views: 171
Reputation: 3885
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)
}
}
Upvotes: 1
Reputation: 21565
class MyDomain{
JSONElement content
static constraints = {
content nullable: false, blank: false, sqlType: "text" // adapter from Map to String??
}
def setContent(String textContent){
content = JSON.parse(textContent)
}
}
I had to do 2 things.
def content
with JSON content
so that it gets persisted, see Grails Domain Constructor is not Groovy Constructordef setContent()
.As content
is JSONElement
use JSONObject
and JSONArray
as concrete classes.
Upvotes: 0