Skip to content

Instantly share code, notes, and snippets.

@andrewspencer
Created December 15, 2010 14:10
Show Gist options
  • Save andrewspencer/741975 to your computer and use it in GitHub Desktop.
Save andrewspencer/741975 to your computer and use it in GitHub Desktop.
Base class for Hibernate UserTypes
package net.andrewspencer.util.hibernate;
import java.io.Serializable;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashMap;
import java.util.Map;
import org.hibernate.HibernateException;
import org.hibernate.usertype.UserType;
/**
* <p>
* Base class for Hibernate UserTypes.
* </p>
* <p>
* This class handles all the mechanics except for the conversion itself
* between JDBC and entity values, for which you provide an instance of JdbcEntityConverter.
*
* @author Andrew Spencer
*/
public class UserTypeSupport<MappedClass, JdbcClass> implements UserType {
/**
* Conversion strategy between the value seen by JDBC and the representation
* used in the entity class.
*
* @param <MappedClass>
* The class of the property as declared in the entity
* @param <JdbcClass>
* The class of the value returned by or passed to JDBC
* (JDBC must be able to convert between this class and
* the SQL type; the JDBC specs list the available conversions).
* @author spencera
*/
public interface JdbcEntityConverter<MappedClass, JdbcClass> {
/**
* Converts the JDBC value to the value mapped and exposed by the entity
*
* @param value
* the value returned by JDBC (guaranteed non null)
* @return the value to be set in the entity
* @throws SQLException
*/
MappedClass jdbcToEntity(JdbcClass databaseValue) throws SQLException;
/**
* @param objectValue
* the value present in the entity (guaranteed non null)
* @return the value to pass to JDBC
*/
Object entityToJdbc(MappedClass objectValue);
}
private Class<MappedClass> mappedClass = null;
private Class<JdbcClass> jdbcClass = null;
private int sqlType;
private JdbcEntityConverter<MappedClass, JdbcClass> jdbcEntityConverter;
/**
* @param mappedClass
* The class of the property defined on the entity
* @param jdbcClass
* The class of the value passed to or returned from JDBC
* @param sqlType
* The SQL type: one of the constants defined by java.sql.Types
* @param jdbcEntityConverter
* The conversion strategy
*/
protected UserTypeSupport(final Class<MappedClass> mappedClass, final Class<JdbcClass> jdbcClass,
final int sqlType, final JdbcEntityConverter<MappedClass, JdbcClass> databaseRepresentation) {
if (mappedClass == null) {
throw new NullPointerException("mappedClass == null");
}
if (jdbcClass == null) {
throw new NullPointerException("jdbcClass == null");
}
if (converter == null) {
throw new NullPointerException("converter == null");
}
if (!(jdbcClass.equals(Integer.class) || jdbcClass.equals(Long.class) || jdbcClass.equals(String.class))) {
throw new IllegalArgumentException("Seuls Integer, Long et String pris en charge actuellement : voir retrieveFromResultSetAsRequestedType()");
}
this.mappedClass = mappedClass;
this.jdbcClass = jdbcClass;
this.sqlType = sqlType;
this.jdbcEntityConverter = databaseRepresentation;
}
public int[] sqlTypes() {
return new int[] {sqlType};
}
public Class<MappedClass> returnedClass() {
return mappedClass;
}
public Object nullSafeGet(final ResultSet resultSet, final String[] names, final Object owner)
throws HibernateException, SQLException {
@SuppressWarnings("unchecked")
JdbcClass dbValue =
(JdbcClass) retrieveFromResultSetAsRequestedType(resultSet, names[0]);
if (dbValue == null) {
return null;
}
return jdbcEntityConverter.jdbcToEntity(dbValue);
}
private Object retrieveFromResultSetAsRequestedType(final ResultSet resultSet, final String columnName) throws SQLException {
if (jdbcClass.equals(Integer.class)) {
return Integer.valueOf(resultSet.getInt(columnName));
}
if (jdbcClass.equals(Long.class)) {
return Long.valueOf(resultSet.getLong(columnName));
}
if (jdbcClass.equals(String.class)) {
return resultSet.getString(columnName);
}
throw new IllegalStateException("should never happen given the check in constructor");
}
public void nullSafeSet(final PreparedStatement preparedStatement, final Object value, final int index)
throws HibernateException, SQLException {
if (null == value) {
preparedStatement.setNull(index, sqlType);
} else {
@SuppressWarnings("unchecked") // type must be <MappedClass> if Hibernate mapping is correct
MappedClass valueCast = (MappedClass) value;
preparedStatement.setObject(index, jdbcEntityConverter.entityToJdbc(valueCast), sqlType);
}
}
public Object deepCopy(final Object value) throws HibernateException {
return value;
}
public boolean isMutable() {
return false;
}
public Object assemble(final Serializable cached, final Object owner) throws HibernateException {
return cached;
}
public Serializable disassemble(final Object value) throws HibernateException {
return (Serializable) value;
}
public Object replace(final Object original, final Object target, final Object owner)
throws HibernateException {
return original;
}
public int hashCode(final Object x) throws HibernateException {
return x.hashCode();
}
public boolean equals(final Object x, final Object y) throws HibernateException {
if (x == y) {
return true;
}
if (null == x || null == y) {
return false;
}
return x.equals(y);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment