raimund@1299: /* Copyright (C) 2013 by Bundesamt fuer Strahlenschutz raimund@1299: * Software engineering by Intevation GmbH raimund@1299: * raimund@1299: * This file is Free Software under the GNU GPL (v>=3) raimund@1299: * and comes with ABSOLUTELY NO WARRANTY! Check out raimund@1299: * the documentation coming with IMIS-Labordaten-Application for details. raimund@1299: */ raimund@1299: package de.intevation.lada.util.data; raimund@1299: raimund@1299: import java.io.IOException; raimund@1299: import java.io.Serializable; raimund@1299: import java.sql.PreparedStatement; raimund@1299: import java.sql.ResultSet; raimund@1299: import java.sql.SQLException; raimund@1299: import java.sql.Types; raimund@1299: raimund@1299: import org.hibernate.HibernateException; raimund@1299: import org.hibernate.engine.spi.SessionImplementor; raimund@1299: import org.hibernate.usertype.UserType; raimund@1299: raimund@1299: import com.fasterxml.jackson.databind.JsonNode; raimund@1299: import com.fasterxml.jackson.databind.ObjectMapper; raimund@1299: raimund@1299: /** raimund@1299: * Implementation for a new data type in the postgresql/postgis jdbc driver. raimund@1299: * raimund@1299: * @author Raimund Renkert raimund@1299: */ raimund@1299: public class JsonObjectType implements UserType { raimund@1299: /** raimund@1299: * Reconstruct an object from the cacheable representation. At the very raimund@1299: * least this method should perform a deep copy if the type is mutable. raimund@1299: * (optional operation) raimund@1299: * raimund@1299: * @param cached raimund@1299: * the object to be cached raimund@1299: * @param owner raimund@1299: * the owner of the cached object raimund@1299: * @return a reconstructed object from the cachable representation raimund@1299: * @throws HibernateException raimund@1299: */ raimund@1299: @Override raimund@1299: public Object assemble(Serializable cached, Object owner) throws HibernateException { raimund@1299: return this.deepCopy(cached); raimund@1299: } raimund@1299: raimund@1299: /** raimund@1299: * Return a deep copy of the persistent state, stopping at entities and st raimund@1299: * collections. It is not necessary to copy immutable objects, or null raimund@1299: * values, in which case it is safe to simple return the argument. raimund@1299: * raimund@1299: * @param value raimund@1299: * the object to be cloned, which may be null raimund@1299: * raimund@1299: * @return object a copy raimund@1299: * @throws HibernateException raimund@1299: */ raimund@1299: @Override raimund@1299: public Object deepCopy(Object value) throws HibernateException { raimund@1299: return value; raimund@1299: } raimund@1299: raimund@1299: /** raimund@1299: * Transform the object into its cacheable representation. At the very least raimund@1299: * this method should perform a deep copy if the type is mutable. That may raimund@1299: * not be enough for some implementations, however; for example, raimund@1299: * associations must be cached as identifier values. (optional operation) raimund@1299: * raimund@1299: * @param value raimund@1299: * the object to be cached raimund@1299: * @return a cachable representation of the object raimund@1299: * @throws HibernateException raimund@1299: */ raimund@1299: @Override raimund@1299: public Serializable disassemble(Object value) throws HibernateException { raimund@1299: return (String) this.deepCopy(value); raimund@1299: } raimund@1299: raimund@1299: /** raimund@1299: * Compare two instances of the class mapped by this type for persistence raimund@1299: * "equality". Equality of the persistence state. raimund@1299: * raimund@1299: * @param x raimund@1299: * @param y raimund@1299: * @return boolean raimund@1299: * @throws HibernateException raimund@1299: */ raimund@1299: @Override raimund@1299: public boolean equals(Object x, Object y) throws HibernateException { raimund@1299: if (x == null) { raimund@1299: return y == null; raimund@1299: } raimund@1299: return x.equals(y); raimund@1299: } raimund@1299: raimund@1299: /** raimund@1299: * Get a hashcode for the instance, consistent with persistence "equality". raimund@1299: */ raimund@1299: @Override raimund@1299: public int hashCode(Object x) throws HibernateException { raimund@1299: return x.hashCode(); raimund@1299: } raimund@1299: raimund@1299: /** raimund@1299: * Are objects of this type mutable? raimund@1299: * raimund@1299: * @return boolean raimund@1299: */ raimund@1299: @Override raimund@1299: public boolean isMutable() { raimund@1299: return true; raimund@1299: } raimund@1299: raimund@1299: /** raimund@1299: * Retrieve an instance of the mapped class from a JDBC resultset. raimund@1299: * Implementors should handle possibility of null values. raimund@1299: * raimund@1299: * @param rs raimund@1299: * a JDBC result set raimund@1299: * @param names raimund@1299: * the column names raimund@1299: * @param session raimund@1299: * @param owner raimund@1299: * the containing entity raimund@1299: * @return raimund@1299: * @throws HibernateException raimund@1299: * @throws SQLException raimund@1299: */ raimund@1299: @Override raimund@1299: public Object nullSafeGet(ResultSet rs, String[] names, SessionImplementor session, Object owner) throws HibernateException, SQLException { raimund@1299: ObjectMapper mapper = new ObjectMapper(); raimund@1299: JsonNode node = null; raimund@1299: try { raimund@1299: node = mapper.readTree(rs.getString(names[0])); raimund@1299: return node; raimund@1299: } catch (IOException e) { raimund@1299: e.printStackTrace(); raimund@1299: } raimund@1299: return mapper.createObjectNode(); raimund@1299: } raimund@1299: raimund@1299: /** raimund@1299: * Write an instance of the mapped class to a prepared statement. raimund@1299: * Implementors should handle possibility of null values. A multi-column raimund@1299: * type should be written to parameters starting from index raimund@1299: * raimund@1299: * @param st raimund@1299: * a JDBC prepared statement raimund@1299: * @param value raimund@1299: * the object to write raimund@1299: * @param index raimund@1299: * statement parameter index raimund@1299: * @param session raimund@1299: * @throws HibernateException raimund@1299: * @throws SQLException raimund@1299: */ raimund@1299: @Override raimund@1299: public void nullSafeSet(PreparedStatement st, Object value, int index, SessionImplementor session) throws HibernateException, SQLException { raimund@1299: if (value == null) { raimund@1299: st.setNull(index, Types.OTHER); raimund@1299: return; raimund@1299: } raimund@1299: st.setObject(index, value, Types.OTHER); raimund@1299: } raimund@1299: raimund@1299: /** raimund@1299: * During merge, replace the existing (target) values in the entity we are raimund@1299: * merging to with a new (original) value from the detched entity we are raimund@1299: * merging. For immutable objects, or null values, it is safe to return a raimund@1299: * copy of the first parameter. For the objects with component values, it raimund@1299: * might make sense to recursively replace component values raimund@1299: * raimund@1299: * @param original raimund@1299: * the value from the detched entity being merged raimund@1299: * @param target raimund@1299: * the value in the managed entity raimund@1299: * @param owner raimund@1299: * @return the value to be merged raimund@1299: * @throws HibernateException raimund@1299: */ raimund@1299: @Override raimund@1299: public Object replace(Object original, Object target, Object owner) throws HibernateException { raimund@1299: return original; raimund@1299: } raimund@1299: raimund@1299: /** raimund@1299: * The class returned by nullSafeGet() raimund@1299: * raimund@1299: * @return Class raimund@1299: */ raimund@1299: @Override raimund@1299: public Class returnedClass() { raimund@1299: return String.class; raimund@1299: } raimund@1299: raimund@1299: /** raimund@1299: * Returns the SQL type codes for the columns mapped by this type. The codes raimund@1299: * are defined on java.sql.Types raimund@1299: * raimund@1299: * @return int[] the typecodes raimund@1299: * @see java.sql.Types raimund@1299: */ raimund@1299: @Override raimund@1299: public int[] sqlTypes() { raimund@1299: return new int[] { Types.JAVA_OBJECT }; raimund@1299: } raimund@1299: }