Java 参数值与预期类型不匹配

Java 参数值与预期类型不匹配,java,hibernate,classloader,glassfish-4,Java,Hibernate,Classloader,Glassfish 4,我有一个带有状态列表的枚举(例如) 我的数据库中的列的类型为enum。当我试图通过使用setParameter(“关键字”,State.RETRY)在查询中设置参数来执行Hibernate查询时,我收到的错误是 参数值[重试]与预期类型不匹配 [package.name.State(不适用)] 在我的域的Glassfish 4.1 server.log中。我正在使用Hibernate4.3.6 在查看Hibernate的源代码时,我看到出现错误是因为org.Hibernate.jpa.spi.B

我有一个带有状态列表的枚举(例如)

我的数据库中的列的类型为enum。当我试图通过使用
setParameter(“关键字”,State.RETRY)在查询中设置参数来执行Hibernate查询时,我收到的错误是

参数值[重试]与预期类型不匹配 [package.name.State(不适用)]

在我的域的Glassfish 4.1 server.log中。我正在使用Hibernate4.3.6

在查看Hibernate的源代码时,我看到出现错误是因为
org.Hibernate.jpa.spi.BaseQueryImpl
中的行958-960

private static boolean isValidBindValue(Class expectedType, Object value, TemporalType temporalType) {
        if ( expectedType.isInstance( value ) ) {
            return true;
        }
...
return false;
}
isValidBindValue
返回false,因此我得到消息

它打印出
字符串
相当于
枚举
值,因为这一行:

String.format("Parameter value [%s] did not match expected type [%s (%s)]",
               bind,
               parameterType.getName(),
               extractName( temporalType )
             )
通过调用表示枚举状态的
对象上的
toString
方法,将
bind
对象隐式转换为字符串值。重试

那么我如何才能说服Hibernate相信
State.RETRY
State
的一个实例呢

从2013年4月开始,Hibernate似乎更新为JPA 2.1规范,该规范在本次提交中更加严格:

实体注释如下:

@Basic(optional = false)
@Column(name = "state")
@Enumerated(EnumType.String)
private State state;
编辑:


My
RetryState
枚举由
EarLibClassLoader
加载。而
Query
是由URLClassLoader加载的,
EntityManager
是由另一个类加载程序加载的。

我想主要问题是您试图在数据库端使用枚举数据类型。不建议这样做,因为它通常需要专有的枚举类型,而JPA实现可能不支持这种类型(例如Hibernate)。有关详细信息,请参见关于类似问题的

此外,还有注释

@Enumerated(EnumType.String)
@Basic(optional = false)
@Column(name = "state", columnDefinition = "enum('UP','DOWN','RETRY')")
@Enumerated(EnumType.String)
private State state;
您的意思是明确希望将值保存为数据库中的字符串。如果实际的列类型是某个枚举,我希望这会失败。Hibernate代码的更改可能是为了防止这些问题,迫使您使用varcharinteger

可能的解决方案:

A)

使用带有
@枚举(EnumType.String)
的varchar列或带有
@枚举的int列

B)

您可以尝试通过注释指定枚举列

@Enumerated(EnumType.String)
@Basic(optional = false)
@Column(name = "state", columnDefinition = "enum('UP','DOWN','RETRY')")
@Enumerated(EnumType.String)
private State state;
C)

您可以尝试通过hibernate XML映射文件指定枚举类:

<property name="type" column="type" not-null="true">
    <type name="org.hibernate.type.EnumType">
        <param name="enumClass">package.name.State</param>
        <param name="type">12</param>
        <!-- 12 is java.sql.Types.VARCHAR -->
    </type> 
</property>

package.name.State
12
另请参见:


通过将带有JPA注释的类和枚举类放入域dir/lib/applib目录,解决了这一问题。您必须将这些类放置在domain dir/lib/applib目录中的JAR中,然后使用
--库jar1、jar2等
在deploy命令上使用asadmin指定JAR。列出多个JAR文件时,不要在逗号后加空格

此外,我有一个具有EJB远程接口的通用JAR,因此我必须将我的JPA类分解成一个新的JAR,并将它们也放在我的applibs目录中。然后,我将带有EJB远程接口的JAR放入我的EAR\lib目录


lib/applibs目录中的jar由URLClassLoader加载。EAR\lib中的jar是由EARLibClassLoader加载的

我在一个项目中遇到了同样的问题,但是在多次尝试之后,创建一个表来替换我的枚举更有意义。然而,使用Jackson似乎有效

你确定
私有状态参考正确的枚举?你可能导入错了?@Tom:只是仔细检查了一下,枚举就在一个普通的罐子里。在我的bean和实体注释类中,它引用了公共jar中的相同枚举。