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

标签 java hibernate jpa enums playframework

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

所以我想知道是否有一个基于 Hibernate 的 play 的好的解决方案。也许通过破解 JPAPlugin?

[更新 1] 我开始尝试使用 @type-annotation 的第二种解决方案。不幸的是,这在 hibernate 3.6(由 play 1.2.2 使用)中被打破。 TypeFactory.basic() 不是 available任何更多。但是按照文档我找不到解决方法。

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

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

最佳答案

不确定它是否真的有效,但一种可能的解决方案如下:

  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>"),
    })
    

但我不确定这对于这样的问题是否没有太大的魔力。也许有人可以给我一个建议。

关于java - 如何在游戏中存储具有固定值的枚举,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6774517/

相关文章:

java - Hibernate JPA - PESSIMISTIC.WRITE 不起作用

java - 如何检测交易类型: JTA or Resource Local from java code?

java - 比较类对象

hibernate - @ManyToOne 单向映射

java - jasypt ZeroSaltGenerator在Spring + Hibernate中生成不同的加密字符串

java - hibernate 4.0 中的 HibernateDaoSupport

java - Play + JPA + Hibernate + PostgreSQL : Cannot create Tables

java - java中的浮点到长类型转换问题

java - 删除矩形之间的间距 JavaFX

带有文档过滤器的 Java REGEX