java.lang.verifyError 在休眠特定用户类型上
Posted
技术标签:
【中文标题】java.lang.verifyError 在休眠特定用户类型上【英文标题】:java.lang.verifyError on hibernate specific usertype 【发布时间】: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());
【问题讨论】:
【参考方案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());
而且...到目前为止,一切都很好。
【讨论】:
以上是关于java.lang.verifyError 在休眠特定用户类型上的主要内容,如果未能解决你的问题,请参考以下文章
API < 21 的 java.lang.VerifyError
java.lang.VerifyError:在分支目标 73 处期望堆栈图帧
java.lang.VerifyError:在分支目标 73 处期望堆栈图帧