java.lang.AbstractMethodError: at UserType.nullSafeSet()

java.lang.AbstractMethodError: at UserType.nullSafeSet()

我有自定义 enum 值要保存在数据库中。为此,我实施了 StringValuedEnum, StringValuedEnumType and StingValuedEnumReflect 并且我的 enum 实施了 StringValuedEnum.

当我 运行 我的代码使用手动管理的 JPA 时,一切正常,我的枚举值保存在数据库中。但是一旦我 运行 带有容器管理的 JPA (Wildfly 8.2) 的应用程序,我在刷新实体管理器时收到以下错误:

Caused by: java.lang.AbstractMethodError: yyy.xxx.util.StringValuedEnumType.nullSafeSet(Ljava/sql/PreparedStatement;Ljava/lang/Object;ILorg/hibernate/engine/spi/SessionImplementor;)V
at org.hibernate.type.CustomType.nullSafeSet(CustomType.java:158) [hibernate-core-4.3.7.Final.jar:4.3.7.Final]
at org.hibernate.persister.entity.AbstractEntityPersister.dehydrate(AbstractEntityPersister.java:2843) [hibernate-core-4.3.7.Final.jar:4.3.7.Final]
at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:3121) [hibernate-core-4.3.7.Final.jar:4.3.7.Final]
at org.hibernate.persister.entity.AbstractEntityPersister.insert(AbstractEntityPersister.java:3581) [hibernate-core-4.3.7.Final.jar:4.3.7.Final]
at org.hibernate.action.internal.EntityInsertAction.execute(EntityInsertAction.java:104) [hibernate-core-4.3.7.Final.jar:4.3.7.Final]
at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:463) [hibernate-core-4.3.7.Final.jar:4.3.7.Final]
at org.hibernate.engine.spi.ActionQueue.executeActions(ActionQueue.java:349) [hibernate-core-4.3.7.Final.jar:4.3.7.Final]
at org.hibernate.event.internal.AbstractFlushingEventListener.performExecutions(AbstractFlushingEventListener.java:350) [hibernate-core-4.3.7.Final.jar:4.3.7.Final]
at org.hibernate.event.internal.DefaultFlushEventListener.onFlush(DefaultFlushEventListener.java:56) [hibernate-core-4.3.7.Final.jar:4.3.7.Final]
at org.hibernate.internal.SessionImpl.flush(SessionImpl.java:1222) [hibernate-core-4.3.7.Final.jar:4.3.7.Final]
at org.hibernate.jpa.spi.AbstractEntityManagerImpl.flush(AbstractEntityManagerImpl.java:1335) [hibernate-entitymanager-4.3.7.Final.jar:4.3.7.Final]
at org.jboss.as.jpa.container.AbstractEntityManager.flush(AbstractEntityManager.java:457) [wildfly-jpa-8.2.1.Final.jar:8.2.1.Final]
at zzz.ejb.facades.EntityManagerFacade.createObject(EntityManagerFacade.java:2024) [zzz-ejb.jar:]
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) [rt.jar:1.8.0_66]
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) [rt.jar:1.8.0_66]
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) [rt.jar:1.8.0_66]
at java.lang.reflect.Method.invoke(Method.java:497) [rt.jar:1.8.0_66]
at org.jboss.as.ee.component.ManagedReferenceMethodInterceptor.processInvocation(ManagedReferenceMethodInterceptor.java:52)
at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:309)
at org.jboss.invocation.WeavedInterceptor.processInvocation(WeavedInterceptor.java:53)
at org.jboss.as.ee.component.interceptors.UserInterceptorFactory.processInvocation(UserInterceptorFactory.java:63)
at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:309)
at org.jboss.invocation.InterceptorContext$Invocation.proceed(InterceptorContext.java:407)
at org.jboss.as.weld.ejb.Jsr299BindingsInterceptor.doMethodInterception(Jsr299BindingsInterceptor.java:82) [wildfly-weld-8.2.1.Final.jar:8.2.1.Final]
at org.jboss.as.weld.ejb.Jsr299BindingsInterceptor.processInvocation(Jsr299BindingsInterceptor.java:93) [wildfly-weld-8.2.1.Final.jar:8.2.1.Final]
at org.jboss.as.ee.component.interceptors.UserInterceptorFactory.processInvocation(UserInterceptorFactory.java:63)
at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:309)
at org.jboss.invocation.WeavedInterceptor.processInvocation(WeavedInterceptor.java:53)
at org.jboss.as.ee.component.interceptors.UserInterceptorFactory.processInvocation(UserInterceptorFactory.java:63)
at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:309)
at org.jboss.as.ejb3.component.invocationmetrics.ExecutionTimeInterceptor.processInvocation(ExecutionTimeInterceptor.java:43) [wildfly-ejb3-8.2.1.Final.jar:8.2.1.Final]
at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:309)
at org.jboss.as.jpa.interceptor.SBInvocationInterceptor.processInvocation(SBInvocationInterceptor.java:47) [wildfly-jpa-8.2.1.Final.jar:8.2.1.Final]
at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:309)
at org.jboss.invocation.InterceptorContext$Invocation.proceed(InterceptorContext.java:407)
at org.jboss.weld.ejb.AbstractEJBRequestScopeActivationInterceptor.aroundInvoke(AbstractEJBRequestScopeActivationInterceptor.java:46) [weld-core-impl-2.2.6.Final.jar:2014-10-03 10:05]
at org.jboss.as.weld.ejb.EjbRequestScopeActivationInterceptor.processInvocation(EjbRequestScopeActivationInterceptor.java:83) [wildfly-weld-8.2.1.Final.jar:8.2.1.Final]
at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:309)
at org.jboss.as.ee.concurrent.ConcurrentContextInterceptor.processInvocation(ConcurrentContextInterceptor.java:45) [wildfly-ee-8.2.1.Final.jar:8.2.1.Final]
at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:309)
at org.jboss.invocation.InitialInterceptor.processInvocation(InitialInterceptor.java:21)
at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:309)
at org.jboss.invocation.ChainedInterceptor.processInvocation(ChainedInterceptor.java:61)
at org.jboss.as.ee.component.interceptors.ComponentDispatcherInterceptor.processInvocation(ComponentDispatcherInterceptor.java:53)
at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:309)
at org.jboss.as.ejb3.component.interceptors.NonPooledEJBComponentInstanceAssociatingInterceptor.processInvocation(NonPooledEJBComponentInstanceAssociatingInterceptor.java:59) [wildfly-ejb3-8.2.1.Final.jar:8.2.1.Final]
at org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:309)
at org.jboss.as.ejb3.tx.CMTTxInterceptor.invokeInCallerTx(CMTTxInterceptor.java:251) [wildfly-ejb3-8.2.1.Final.jar:8.2.1.Final] 

看起来问题出在池化(堆栈跟踪中显示了非池化的 EJB 组件)。

奇怪的是我无法调试它来理解这个问题:调试器不会在方法中放置的任何断点处停止,System.out.println() 也不会起作用。

问题

UserType 方法 nullSafeSet 和 nullSafeGet 的签名已从 Hibernate 3 更改为 hibernate 4。您需要做的是在您的自定义用户类型中更新这些方法。

改成:

public void nullSafeSet(PreparedStatement st, Object value, int index, SessionImplementor session) throws HibernateException, SQLException

对此:

public void nullSafeSet(PreparedStatement st, Object value, int index, SharedSessionContractImplementor session) throws HibernateException, SQLException

如您所见,"SessionImplementor" 参数的类型已更改。

我把我的解决方案放在这里,以便其他人可以看到并可能也使用,但如果能提供确切的答案,将不胜感激。

我只是通过使用 @Enumerated(EnumType.STRING) 注释我的实体列来解决我的问题,这样枚举名称就会被保留下来。这对我的枚举没问题......但是如果枚举有一些字段并且你想保留字段的值,那么你可以在你的实体中执行以下操作 class:

@Entity
@Table(name = "TABLE_NAME")
public class EntityClass {

    // columns

    @Transient
    private EnumClass enumObj;

    @Column(name = "ENUM_COL_NAME")
    private String enumColField;

    // ......................

    @PostLoad
    void fillTransient() {
        enumObj = EnumClass.fromValue(enumColField);
    }

    @PrePersist
    @PreUpdate
    void fillPersistent() {
        if (enumObj != null) {
            enumColField = enumObj.getField();
        }
    }
}

这非常有效,即使您的枚举有多个字段并且您希望将它们分别保存在数据库中,那么您可以拥有任意多的列,填充这些列并以提供的方式检索它们。