package de.flower.rmt.model.db.type; import org.apache.commons.lang3.StringUtils; import org.hibernate.HibernateException; import org.hibernate.type.descriptor.JdbcTypeNameMapper; import org.hibernate.usertype.UserType; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.Serializable; import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Types; import java.util.ArrayList; import java.util.List; /** * User type to store lists of objects in a single varchar. * * @param T type of list element * @author flowerrrr */ public abstract class AbstractListType<T> implements UserType { private final static Logger log = LoggerFactory.getLogger(AbstractListType.class); private static final int[] SQL_TYPES = new int[]{Types.VARCHAR,}; @Override public int[] sqlTypes() { return SQL_TYPES; } @Override public Class returnedClass() { return ArrayList.class; } @Override public boolean equals(final Object x, final Object y) throws HibernateException { if (x == y) { return true; } if (x == null || y == null) { return false; } List<T> dtx = (List<T>) x; List<T> dty = (List<T>) y; return dtx.equals(dty); } @Override public int hashCode(final Object x) throws HibernateException { return x.hashCode(); } @Override public Object nullSafeGet(final ResultSet rs, final String[] names, final Object owner) throws HibernateException, SQLException { String serialized = rs.getString(names[0]); if (log.isTraceEnabled()) { log.trace("found [" + serialized + "] as column [" + names[0] + "]"); } return assemble(serialized, owner); } @Override public void nullSafeSet(final PreparedStatement st, final Object value, final int index) throws HibernateException, SQLException { String string = (String) disassemble(value); if (log.isTraceEnabled()) { log.trace("binding parameter [" + index + "] as [" + JdbcTypeNameMapper.getTypeName(SQL_TYPES[0]) + "] - " + string); } if (value == null) { st.setNull(index, SQL_TYPES[0]); } else { st.setString(index, string); } } @Override public Object deepCopy(final Object value) throws HibernateException { return (value == null) ? null : new ArrayList((List) value); } @Override public boolean isMutable() { return true; } @Override public Serializable disassemble(final Object value) throws HibernateException { return list2String((List<T>) value); } @Override public Object assemble(final Serializable cached, final Object owner) throws HibernateException { return string2List((String) cached); } @Override public Object replace(final Object original, final Object target, final Object owner) throws HibernateException { return deepCopy(original); } public String list2String(final List<T> list) { if (list == null) { return null; } List<String> strings = new ArrayList<String>(); for (T object : list) { strings.add(toString(object)); } return StringUtils.join(strings, "|"); } public List<T> string2List(final String string) { if (string == null) { return null; } String[] strings = StringUtils.split(string, "|"); List<T> list = new ArrayList(); for (String s : strings) { list.add(fromString(s)); } return list; } /** * Subclasses should override these methods with marshalling/unmarshalling code. * * @param list * @return */ public abstract String toString(T object); public abstract T fromString(String string); public static class StringListType extends AbstractListType<String> { @Override public String toString(final String object) { return object; } @Override public String fromString(final String string) { return string; } } }