【问题标题】:java.lang.verifyError on hibernate specific usertypejava.lang.verifyError 在休眠特定用户类型上
【发布时间】:2011-01-20 06:39:06
【问题描述】:

我们一直在使用 GenericEnumUserType 进行可扩展枚举,但我们的类无法在 Hibernate 3.6+ 容器上的 JBoss 6 中加载。

抛出以下错误

#abc state=Create: java.lang.NoSuchMethodError: org.hibernate.type.Type
Factory.basic(Ljava/lang/String;)Lorg/hibernate/type/Type;

关于以下代码

type = (NullableType)TypeFactory.basic(identifierType.getName());

【问题讨论】:

    标签: hibernate


    【解决方案1】:

    不幸的是,如果您需要基于 Enum 的序数或名称以外的其他内容进行序列化,则 @​​Enumerated 不起作用。我设法找到了一个解决方案(从here 稍作修改)。

    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 = "name";
        private static final String defaultValueOfMethodName = "valueOf";
        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] );
            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;
        }
    }
    

    【讨论】:

    • 这一直有效,直到我迁移到最新版本的休眠。 new TypeResolver() 自 5.3 起已弃用,我还没有找到任何替代方案。
    【解决方案2】:

    Hibernate 3.6 中不再有 TypeFactory.basic(String) 了。比较 javadocs:

    http://docs.jboss.org/hibernate/core/3.6/javadocs/org/hibernate/type/TypeFactory.html http://docs.jboss.org/hibernate/core/3.3/api/org/hibernate/type/TypeFactory.html

    我认为现在是时候从自定义 UserType 转移到标准 @Enumerated 了 :-)

    【讨论】:

    • 不幸的是,如果您基于 Enum 序号或名称进行序列化,则只能使用 @Enumerated。在某些情况下这是不合适的。
    • 我可以确认 mtpettyp 在说什么。一个常见的情况是当您用枚举替换“幻数”时,您仍然必须保留原始数据。
    【解决方案3】:

    我查看了TypeResolver 的代码并注意到basic 方法的内部实现,该方法使用尚未弃用的类。所以,我换了

    TypeResolver tr = new TypeResolver();
    type = (AbstractSingleColumnStandardBasicType)tr.basic( identifierType.getName() );
    

    type = (AbstractSingleColumnStandardBasicType<? extends Object>) new TypeConfiguration()
           .getBasicTypeRegistry().getRegisteredType(identifierType.getName());
    

    而且...到目前为止,一切都很好。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-01-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2016-11-13
      相关资源
      最近更新 更多