A Hibernate UserType defines a (custom) way how to save Java objects into the database. Basically, it defines how the object is serialized to be persisted in the database and how the object is (re)created from the serialized data stored in the database.
Here is a UserType that I’ve written to persist objects of type JSONObject. I’m using the JSON implementation from json.org; for other JSON libraries the UserType should be very similar.
package net.janjonas.example; import java.io.Serializable; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Types; import org.hibernate.HibernateException; import org.hibernate.usertype.UserType; import org.json.JSONException; import org.json.JSONObject; /** * Hibernate user type to persist JSONObject * * @see http://www.json.org/javadoc/org/json/JSONObject.html * @see http://docs.jboss.org/hibernate/stable/annotations/api/org/hibernate/usertype/UserType.html * @author "Jan Jonas <mail@janjonas.net>" */ public class JSONObjectUserType implements UserType { private static final int[] SQL_TYPES = { Types.LONGVARCHAR }; @Override public Object assemble(Serializable cached, Object owner) throws HibernateException { return deepCopy(cached); } @Override public Object deepCopy(Object value) throws HibernateException { if (value == null) return value; try { return new JSONObject(((JSONObject)value).toString()); } catch (JSONException e) { throw new RuntimeException(e); } } @Override public Serializable disassemble(Object value) throws HibernateException { return ((JSONObject)value).toString(); } @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 ((JSONObject)x).toString().hashCode(); } @Override public boolean isMutable() { return true; } @Override public Object nullSafeGet(ResultSet rs, String[] names, Object owner) throws HibernateException, SQLException { if (!rs.wasNull()) { try { return new JSONObject(rs.getString(names[0])); } catch (JSONException e) { throw new RuntimeException(e); } } return null; } @Override public void nullSafeSet(PreparedStatement st, Object value, int index) throws HibernateException, SQLException { if (value == null) { st.setNull(index, SQL_TYPES[0]); } else { st.setString(index, ((JSONObject)value).toString()); } } @Override public Object replace(Object original, Object target, Object owner) throws HibernateException { return deepCopy(original); } @Override @SuppressWarnings("unchecked") public Class returnedClass() { return JSONObject.class; } @Override public int[] sqlTypes() { return SQL_TYPES; } } |
very useful, thanks for the info!
couple of things I’ve discovered:
I think there’s a bug in equals() – should it be:?
if (x == null) return (y == null);
also I think there’s a bug in nullSafeGet(): rs.wasNull() refers to the last call, not the one it’s about to read.
this will return null if the last column read returned null, ie some other random column that hibernate happened to read from its resultset immediately prior to this one.
a fix would be to check the results of the rs.getString() for null and return a null JSONObject. or call wasNull() after the getString().
please provide the hbm.xml file sample also.
I have used :
which leads to following exception:
Exception in thread “main” java.lang.ExceptionInInitializerError
at utils.HibernateUtils.buildSessionFactory(HibernateUtils.java:20)
at utils.HibernateUtils.(HibernateUtils.java:6)
at client.Client.main(Client.java:20)
Caused by: org.hibernate.MappingException: Could not determine type for: JSONObjectUserType, at table: ELEMENT, for columns: [org.hibernate.mapping.Column(jsonObject)]
at org.hibernate.mapping.SimpleValue.getType(SimpleValue.java:292)
at org.hibernate.mapping.SimpleValue.isValid(SimpleValue.java:276)
at org.hibernate.mapping.Property.isValid(Property.java:207)
at org.hibernate.mapping.PersistentClass.validate(PersistentClass.java:458)
at org.hibernate.mapping.RootClass.validate(RootClass.java:215)
at org.hibernate.cfg.Configuration.validate(Configuration.java:1135)
at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1320)
at utils.HibernateUtils.buildSessionFactory(HibernateUtils.java:17)
… 2 more