如何在游戏中存储具有固定值的枚举

时间:2011-07-21 10:18:26

标签: java hibernate jpa enums playframework

我正在尝试将grails-project转换为playframework。在Grails中,您可以定义一个id,以便将id存储在数据库中(请参阅release notes中的增强的枚举支持)。 我看到similar question,但没有可接受的解决方案。如果我更改CRUD模块的类型会出现问题,因为应该显示Enum的信息会丢失。

所以我想知道是否存在一个很好的解决方案,它基于Hibernate。也许是在破解JPAPlugin?

[更新1]我开始尝试使用@type - 注释的第二个解决方案。不幸的是,这已经被hibernate 3.6(播放1.2.2使用)破坏了。 TypeFactory.basic()不再是available。但是根据文档我无法找到解决方法。

[更新2] hibernate 3.6.1有solution,但在每次使用枚举时定义类型真的很笨拙。

@Type(type="hibernatehelper.GenericEnumUserType", 
            parameters= {
            @Parameter(
                    name  = "enumClass",                      
                    value = "models.Geschlecht"),
        })
public Geschlecht geschlecht = Geschlecht.WEIBLICH; 

1 个答案:

答案 0 :(得分:4)

不确定它是否真的有效,但可能的解决办法如下:

  1. 写了一个泛型类型映射器:

    package hibernatehelper;
    
    import java.io.Serializable;
    import java.lang.reflect.Method;
    import java.sql.PreparedStatement;
    import java.sql.ResultSet;
    import java.sql.SQLException;
    import java.util.Properties;
    import org.hibernate.HibernateException;
    import org.hibernate.type.AbstractSingleColumnStandardBasicType;
    import org.hibernate.type.TypeResolver;
    import org.hibernate.usertype.ParameterizedType;
    import org.hibernate.usertype.UserType;
    
    
    public class GenericEnumUserType implements UserType, ParameterizedType {
    
        private Class <? extends Enum> enumClass;
    
        private Class <?> identifierType;
    
        private Method identifierMethod;
    
        private Method valueOfMethod;
    
        private static final String defaultIdentifierMethodName = "getId";
    
        private static final String defaultValueOfMethodName = "parseId";
    
        private AbstractSingleColumnStandardBasicType type;
    
        private int[] sqlTypes;
    
        @Override
        public void setParameterValues(Properties parameters) {
            String enumClassName = parameters.getProperty("enumClass");
            try {
                enumClass = Class.forName(enumClassName).asSubclass(Enum.class);
            } catch (ClassNotFoundException exception) {
                throw new HibernateException("Enum class not found", exception);
            }
    
            String identifierMethodName =
                    parameters.getProperty("identifierMethod",
                            defaultIdentifierMethodName);
    
            try {
                identifierMethod =
                        enumClass.getMethod(identifierMethodName, new Class[0]);
                identifierType = identifierMethod.getReturnType();
            } catch (Exception exception) {
                throw new HibernateException("Failed to optain identifier method",
                        exception);
            }
    
            TypeResolver tr = new TypeResolver();
            type =
                    (AbstractSingleColumnStandardBasicType) tr.basic(identifierType
                            .getName());
            if (type == null) {
                throw new HibernateException("Unsupported identifier type "
                        + identifierType.getName());
            }
            sqlTypes = new int[] {type.sqlType()};
    
            String valueOfMethodName = parameters.getProperty("valueOfMethod",
                    defaultValueOfMethodName);
            try {
                valueOfMethod = enumClass.getMethod(valueOfMethodName,
                                new Class[] {identifierType});
            } catch (Exception exception) {
                throw new HibernateException("Failed to optain valueOf method",
                        exception);
            }
        }
    
        @Override
        public Class returnedClass() {
            return enumClass;
        }
    
        @Override
        public Object nullSafeGet(ResultSet rs, String[] names, Object owner)
                throws HibernateException, SQLException {
            Object identifier = type.get(rs, names[0]);
            if (identifier == null) {
                return null;
            }
    
            if (valueOfMethod == null) {
    
            }
    
            try {
                return valueOfMethod.invoke(enumClass, new Object[] {identifier});
            } catch (Exception exception) {
                throw new HibernateException(
                        "Exception while invoking valueOfMethod of enumeration class: ",
                        exception);
            }
        }
    
        public void nullSafeSet(PreparedStatement st, Object value, int index)
                throws HibernateException, SQLException {
            try {
                Object identifier =
                        value != null ? identifierMethod.invoke(value,
                                new Object[0]) : null;
                st.setObject(index, identifier);
            } catch (Exception exception) {
                throw new HibernateException(
                        "Exception while invoking identifierMethod of enumeration class: ",
                        exception);
    
            }
        }
    
        @Override
        public int[] sqlTypes() {
            return sqlTypes;
        }
    
        @Override
        public Object assemble(Serializable cached, Object owner)
                throws HibernateException {
            return cached;
        }
    
        @Override
        public Object deepCopy(Object value) throws HibernateException {
            return value;
        }
    
        @Override
        public Serializable disassemble(Object value) throws HibernateException {
            return (Serializable) value;
        }
    
        @Override
        public boolean equals(Object x, Object y) throws HibernateException {
            return x == y;
        }
    
        @Override
        public int hashCode(Object x) throws HibernateException {
            return x.hashCode();
        }
    
        public boolean isMutable() {
            return false;
        }
    
        public Object replace(Object original, Object target, Object owner)
                throws HibernateException {
            return original;
        }
    }
    
  2. 编写了一个Enhancer,它查找来自类型Enum的每个属性,并查看此类型是否具有静态方法parseId。比add the following annotation with javaassist

    @Type(type="hibernatehelper.GenericEnumUserType", 
        parameters= {
        @Parameter(
                name  = "enumClass",                      
                value = "<fullqualified classname of the enum class>"),
    })
    
  3. 但我不确定这对于这样的问题是否有多大的魔力。也许有人可以给我一个建议。