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

发布于 2024-11-25 04:31:28 字数 1214 浏览 0 评论 0原文

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

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

[更新 1] 我开始尝试使用 @type-annotation 的第二个解决方案。不幸的是,这在 hibernate 3.6 中被破坏了(pl​​ay 1.2.2 使用它)。 TypeFactory.basic() 不是 可用了。但根据文档我找不到解决方法。

[更新 2] 有一个用于休眠的解决方案 3.6.1,但是在每次使用枚举时都定义类型确实很笨拙。

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

I'm trying to convert a grails-project to the playframework. In Grails you can define an id so the the id will be stored in the database (see Enhanced Enum Support in the release notes).
I saw a similar question, but with no acceptable solution. If I change the type the CRUD-module get a problem, because the information that a Enum should be shown is lost.

So I wonder if there exists a nice solution with play, which based on Hibernate. Perhaps with hacking the JPAPlugin?

[Update 1] I started to try the second solution with @type-annotation. Unfortunately this become broken with hibernate 3.6 (which is used by play 1.2.2). TypeFactory.basic() is not available any more. But following the documentation I can't find a work around.

[Update 2] There was a solution for hibernate 3.6.1, but it's really clumsy to define the type at each usage of enum.

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

情域 2024-12-02 04:31:28

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

  1. 编写了一个通用类型映射器:

    封装 hibernatehelper;
    
    导入 java.io.Serialized;
    导入java.lang.reflect.Method;
    导入 java.sql.PreparedStatement;
    导入java.sql.ResultSet;
    导入java.sql.SQLException;
    导入java.util.Properties;
    导入 org.hibernate.HibernateException;
    导入 org.hibernate.type.AbstractSingleColumnStandardBasicType;
    导入 org.hibernate.type.TypeResolver;
    导入 org.hibernate.usertype.ParameterizedType;
    导入 org.hibernate.usertype.UserType;
    
    
    公共类 GenericEnumUserType 实现 UserType, ParameterizedType {
    
        私人班级枚举类;
    
        私人课程标识符类型;
    
        私有方法标识符方法;
    
        私有方法 valueOfMethod;
    
        私有静态最终字符串defaultIdentifierMethodName =“getId”;
    
        私有静态最终字符串defaultValueOfMethodName =“parseId”;
    
        私有 AbstractSingleColumnStandardBasicType 类型;
    
        私有 int[] sqlTypes;
    
        @覆盖
        公共无效setParameterValues(属性参数){
            String enumClassName =parameters.getProperty("enumClass");
            尝试 {
                enumClass = Class.forName(enumClassName).asSubclass(Enum.class);
            } catch (ClassNotFoundException 异常) {
                throw new HibernateException("未找到枚举类", 异常);
            }
    
            字符串标识符方法名称=
                    参数.getProperty("identifierMethod",
                            默认标识符方法名称);
    
            尝试 {
                标识符方法=
                        enumClass.getMethod(identifierMethodName, new Class[0]);
                标识符类型 = 标识符方法.getReturnType();
            } catch (异常异常) {
                throw new HibernateException("未能获取标识符方法",
                        例外);
            }
    
            TypeResolver tr = new TypeResolver();
            类型=
                    (AbstractSingleColumnStandardBasicType) tr.basic(identifierType)
                            .getName());
            如果(类型==空){
                throw new HibernateException(“不支持的标识符类型”
                        + 标识符类型.getName());
            }
            sqlTypes = new int[] {type.sqlType()};
    
            String valueOfMethodName =parameters.getProperty("valueOfMethod",
                    方法名称的默认值);
            尝试 {
                valueOfMethod = enumClass.getMethod(valueOfMethodName,
                                新类[] {identifierType});
            } catch (异常异常) {
                throw new HibernateException("无法获取 valueOf 方法",
                        例外);
            }
        }
    
        @覆盖
        公共类 returnClass() {
            返回枚举类;
        }
    
        @覆盖
        public Object nullSafeGet(ResultSet rs, String[] 名称, 对象所有者)
                抛出 HibernateException、SQLException {
            对象标识符 = type.get(rs, names[0]);
            if (标识符 == null) {
                返回空值;
            }
    
            if (valueOfMethod == null) {
    
            }
    
            尝试 {
                return valueOfMethod.invoke(enumClass, new Object[] {identifier});
            } catch (异常异常) {
                抛出新的 HibernateException(
                        "调用枚举类的 valueOfMethod 时出现异常:",
                        例外);
            }
        }
    
        public void nullSafeSet(PreparedStatement st, 对象值, int 索引)
                抛出 HibernateException、SQLException {
            尝试 {
                对象标识符 =
                        值!=空?标识符方法.调用(值,
                                新对象[0]):空;
                st.setObject(索引, 标识符);
            } catch (异常异常) {
                抛出新的 HibernateException(
                        "调用枚举类的identifierMethod时出现异常:",
                        例外);
    
            }
        }
    
        @覆盖
        公共 int[] sqlTypes() {
            返回 sqlTypes;
        }
    
        @覆盖
        公共对象组装(可序列化缓存,对象所有者)
                抛出 HibernateException {
            返回缓存;
        }
    
        @覆盖
        公共对象 deepCopy(对象值) 抛出 HibernateException {
            返回值;
        }
    
        @覆盖
        公共可序列化反汇编(对象值)抛出HibernateException {
            返回(可序列化)值;
        }
    
        @覆盖
        公共布尔等于(对象x,对象y)抛出HibernateException {
            返回 x == y;
        }
    
        @覆盖
        公共 int hashCode(Object x) 抛出 HibernateException {
            返回 x.hashCode();
        }
    
        公共布尔 isMutable() {
            返回假;
        }
    
        公共对象替换(对象原始,对象目标,对象所有者)
                抛出 HibernateException {
            返回原件;
        }
    }
    
  2. 编写了一个增强器,它查找来自 Type Enum 的每个属性,并查看该类型是否具有静态方法 parseId。比 使用 javaassist 添加以下注释

    @Type(type="hibernatehelper.GenericEnumUserType", 
        参数= {
        @范围(
                名称=“枚举类”,                      
                value = "<枚举类的完全限定类名>"),
    })
    

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

Not sure if it's really work, but one possible solution could be the following:

  1. Wrote a generic type mapper:

    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. Wrote an Enhancer which look for every attribute which is from Type Enum and look if this type has a static-method parseId. than add the following annotation with javaassist:

    @Type(type="hibernatehelper.GenericEnumUserType", 
        parameters= {
        @Parameter(
                name  = "enumClass",                      
                value = "<fullqualified classname of the enum class>"),
    })
    

But I'm unsure if this not to much magic for such a problem. Perhaps someone can give me an advice.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文