Database에 날짜를 문자열로 저장했을 경우 사용하는 Hibernate User Type.
java.util.Date
객체를 문자열로 변환해서 저장하고, 읽을 때 문자열에서 다시 Date 객체로 변환한다.
public class StringDateUserType implements UserType, ParameterizedType { public static final String PARAM_FORMAT = "format"; public static final String DEFAULT_FORMAT = "yyyyMMddHHmmss"; private AbstractSingleColumnStandardBasicType type; private int[] sqlTypes = null; private String format; @Override public void setParameterValues(Properties parameters) { format = parameters.getProperty(PARAM_FORMAT, DEFAULT_FORMAT); populateSqlTypes(); } private void populateSqlTypes() { TypeResolver tr = new TypeResolver(); String stringClassName = String.class.getName(); // type은 org.hibernate.type.StringType 으로 사실상 고정값임. type = (AbstractSingleColumnStandardBasicType) tr.basic(stringClassName); sqlTypes = new int[] { type.sqlType() }; } @Override public int[] sqlTypes() { return sqlTypes; } @Override public Class returnedClass() { return Date.class; } @Override public boolean equals(Object x, Object y) throws HibernateException { return Objects.equals(x, y); } @Override public int hashCode(Object x) throws HibernateException { return Objects.hashCode(x); } @Override public Object deepCopy(Object value) throws HibernateException { return dateDeepCopy((Date) value); } @Override public boolean isMutable() { return true; // java.util.Date is mutable } @Override public Serializable disassemble(Object value) throws HibernateException { // TODO : Date는 mutable이라서 deep copy가 맞는듯. 확인 필요. return (Serializable) value; } @Override public Object assemble(Serializable cached, Object owner) throws HibernateException { // TODO : Date는 mutable이라서 deep copy가 맞는듯. 확인 필요. return cached; } @Override public Object replace(Object original, Object target, Object owner) throws HibernateException { return dateDeepCopy((Date) original); } @Override public Object nullSafeGet(ResultSet rs, String[] names, SessionImplementor session, Object owner) throws HibernateException, SQLException { String stringDate = (String) type.get(rs, names[0], session); if (stringDate == null) { // 데이터에 null이 아닌 empty가 있다면 empty 체크도 해야함. log.trace("Found [{}] as column [{}] original value [{}]", null, names[0], stringDate); return null; } try { SimpleDateFormat sdf = new SimpleDateFormat(format); Date parsedDate = sdf.parse(stringDate); log.trace("Found [{}] as column [{}] original value [{}]", parsedDate, names[0], stringDate); return parsedDate; } catch (Exception ex) { throw new HibernateException("Failed to parse [" + stringDate + "] with [" + format + "].", ex); } } @Override public void nullSafeSet(PreparedStatement st, Object value, int index, SessionImplementor session) throws HibernateException, SQLException { try { String formattedDate = null; if (value != null) { SimpleDateFormat sdf = new SimpleDateFormat(format); formattedDate = sdf.format((Date) value); } log.trace("binding parameter [{}] as [{}] - [{}] original value [{}]", index, JdbcTypeNameMapper.getTypeName(sqlTypes[0]), formattedDate, value); st.setObject(index, formattedDate); } catch (Exception ex) { throw new HibernateException("Failed to format date object to string.", ex); } } String getFormat() { return format; } }
@TypeDef(name = "string_datetime", typeClass = StringDateUserType.class, parameters = @Parameter(name = StringDateUserType.PARAM_FORMAT, value = "yyyy/MM/dd HH:mm:ss")), // 이제 @Type(type = "string_datetime") 으로 사용가능해짐. 컬럼은 기본적으로 String의 컬럼인 varchar 계열로 지정됨.