Skip to content

Instantly share code, notes, and snippets.

@tag1216
Last active August 29, 2015 14:11
Show Gist options
  • Save tag1216/b04898934020d25e76df to your computer and use it in GitHub Desktop.
Save tag1216/b04898934020d25e76df to your computer and use it in GitHub Desktop.
Hibernateでenumをコード値で保存
/**
* コード値からenumインスタンスを検索するクラス
*
* http://d.hatena.ne.jp/penult/20110523/1306161406
*
*/
public class Decoder<K extends Serializable, V extends Encodable<K>> {
private Map<K, V> map;
private Decoder(V[] values) {
map = new HashMap<K, V>(values.length);
for (V value : values) {
V old = map.put(value.encode(), value);
// コード値の重複はサポートしない
if (old != null) {
throw new IllegalArgumentException("duplicated code: " + value);
}
}
}
public V decode(K code) {
return map.get(code);
}
// 型引数の指定を省略するため
public static <K1 extends Serializable, V1 extends Encodable<K1>> Decoder<K1, V1> create(V1[] values) {
return new Decoder<K1, V1>(values);
}
}
/**
* コード値を保持するenumに実装するインターフェイス
*
* http://d.hatena.ne.jp/penult/20110523/1306161406
*
*/
public interface Encodable<T extends Serializable> {
T encode();
}
/**
* コード値を保持するenumの永続化
*/
public class EnumUserType implements UserType, DynamicParameterizedType {
public static final String ENUM = "enumClass";
public static final String TYPE = "type";
private Class<? extends Enum<?>> enumClass;
private Class<?> codeType;
private int sqlType = Types.SMALLINT; // before any guessing
@Override
public int[] sqlTypes() {
return new int[] { sqlType };
}
@Override
public Class<? extends Enum<?>> returnedClass() {
// return Aaa.Xxx.class;
return enumClass;
}
@Override
public boolean equals(Object x, Object y) throws HibernateException {
return x == y;
}
@Override
public int hashCode(Object x) throws HibernateException {
return x == null ? 0 : x.hashCode();
}
@Override
public Object nullSafeGet(ResultSet rs, String[] names, SessionImplementor session, Object owner) throws HibernateException, SQLException {
// Object code = rs.getObject(names[0]);
Object code = rs.getObject(names[0]);
if (code != null) {
code =
sqlType == Types.SMALLINT ? rs.getShort(names[0]) :
sqlType == Types.INTEGER ? rs.getInt(names[0]) :
sqlType == Types.VARCHAR ? rs.getString(names[0]) :
code;
}
try {
Method method = ReflectionUtils.findMethod(enumClass, "decode", codeType);
return ReflectionUtils.invokeMethod(method, null, code);
} catch (SecurityException e) {
throw e;
}
// return Aaa.Xxx.decode(code);
}
@Override
public void nullSafeSet(PreparedStatement st, Object value, int index, SessionImplementor session) throws HibernateException, SQLException {
if (value != null) {
// Object code = ((Aaa.Xxx) value).encode();
Method method = ReflectionUtils.findMethod(enumClass, "encode");
Object code = ReflectionUtils.invokeMethod(method, value);
st.setObject(index, code);
}
else {
st.setNull(index, Types.SMALLINT);
}
}
@Override
public Object deepCopy(Object value) throws HibernateException {
return value;
}
@Override
public boolean isMutable() {
return false;
}
@Override
public Serializable disassemble(Object value) throws HibernateException {
return (Serializable) value;
}
@Override
public Object assemble(Serializable cached, Object owner) throws HibernateException {
return cached;
}
@Override
public Object replace(Object original, Object target, Object owner) throws HibernateException {
return target;
}
@SuppressWarnings("unchecked")
@Override
public void setParameterValues(Properties parameters) {
final ParameterType reader = (ParameterType) parameters.get( PARAMETER_TYPE );
enumClass = reader.getReturnedClass();
if (!Encodable.class.isAssignableFrom(enumClass)) {
throw new IllegalArgumentException();
}
codeType = (Class<?>) ((ParameterizedType) enumClass.getGenericInterfaces()[0]).getActualTypeArguments()[0];
if (codeType.equals(Long.class)) {
sqlType = Types.BIGINT;
}
else if (codeType.equals(Integer.class)) {
sqlType = Types.INTEGER;
}
else if (codeType.equals(Short.class)) {
sqlType = Types.SMALLINT;
}
else if (codeType.equals(String.class)) {
sqlType = Types.VARCHAR;
}
else {
sqlType = Types.INTEGER;
}
// String enumClassName = (String) parameters.get( ENUM );
// try {
// enumClass = ReflectHelper.classForName( enumClassName, this.getClass() ).asSubclass( Enum.class );
// }
// catch ( ClassNotFoundException exception ) {
// throw new HibernateException( "Enum class not found", exception );
// }
// final String type = (String) parameters.get( TYPE );
// if ( type != null ) {
// sqlType = Integer.decode( type );
// }
}
}
@SuppressWarnings({ "unchecked", "rawtypes" })
public class StringToEnumConverterFactory implements ConverterFactory<String, Enum> {
ConversionService conversionService;
@Autowired
public StringToEnumConverterFactory(ConversionService conversionService) {
this.conversionService = conversionService;
}
public <T extends Enum> Converter<String, T> getConverter(Class<T> targetType) {
Class<?> enumType = targetType;
while(enumType != null && !enumType.isEnum()) {
enumType = enumType.getSuperclass();
}
Assert.notNull(enumType, "The target type " + targetType.getName()
+ " does not refer to an enum");
return new StringToEnum(enumType);
}
private class StringToEnum<T extends Enum> implements Converter<String, T> {
private Class<T> enumType;
private Class<? extends Encodable> encodableType;
private Class<?> codeType;
public StringToEnum(Class<T> enumType) {
this.enumType = enumType;
if (Encodable.class.isAssignableFrom(enumType)) {
this.encodableType = (Class<? extends Encodable>) enumType;
for (Type type : enumType.getGenericInterfaces()) {
if (type instanceof ParameterizedType && ((ParameterizedType)type).getRawType().equals(Encodable.class)) {
this.codeType = (Class<?>) ((ParameterizedType)type).getActualTypeArguments()[0];
break;
}
}
}
}
public T convert(String source) {
//文字列がnull/ブランク/"null"の時はnullを返す
if (StringUtils.isBlank(source) || StringUtils.equals(source, "null")) {
return null;
}
T value = null;
//コード値->Enumへ変換
if (encodableType != null) {
Method method = BeanUtils.findMethod(enumType, "decode", codeType);
value = (T) ReflectionUtils.invokeMethod(method, null, conversionService.convert(source.trim(), codeType));
}
//Enum名->Enumへ変換
if (value == null) value = (T) Enum.valueOf(this.enumType, source.trim());
return value;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment