Created
December 15, 2010 14:10
-
-
Save andrewspencer/741975 to your computer and use it in GitHub Desktop.
Base class for Hibernate UserTypes
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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