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: }