参数值与预期类型不匹配

时间:2014-12-23 14:09:56

标签: java hibernate classloader glassfish-4

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

enum State
{
   UP,
   DOWN,
   RETRY
};

我的数据库中的列是enum类型。当我尝试通过使用setParameter("keyword", State.RETRY);在查询中设置参数来执行Hibernate查询时,我收到错误

  

参数值[RETRY]与预期类型不匹配   [package.name.State(n / a)]

在我的域名的Glassfish 4.1 server.log中。我正在使用Hibernate 4.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等效的enum值:

String.format("Parameter value [%s] did not match expected type [%s (%s)]",
               bind,
               parameterType.getName(),
               extractName( temporalType )
             )

通过调用代表bind的{​​{1}}上的toString方法,将Object对象隐式转换为字符串值。

那我怎么能说服Hibernate enum State.RETRYState.RETRY的一个实例?

看起来Hibernate已更新为JPA 2.1规范,从2013年4月开始,此规范中更严格:

https://github.com/hibernate/hibernate-orm/commit/84520cd6e36e9207c41528cf9311cae905a86425

该实体注释如下:

State

编辑:

我的@Basic(optional = false) @Column(name = "state") @Enumerated(EnumType.String) private State state; 枚举由RetryState加载。而EarLibClassLoader由URLClassLoader加载,Query由不同的类加载器加载。

3 个答案:

答案 0 :(得分:2)

我猜主要的问题是你试图在数据库端使用枚举数据类型。建议不要这样做,因为它通常需要专有的枚举类型,而JPA实现可能无法很好地支持它(例如Hibernate)。有关详细信息,请参阅类似问题的this answer

此外,使用注释

@Enumerated(EnumType.String)

您说您明确要求,该值在数据库中以 的形式保存。如果真正的列类型是枚举,我希望这会失败。也许Hibernate代码更改试图通过强制您使用 varchar 整数列来防止这些问题。

可能的解决方案:

A)

使用带有@Enumerated(EnumType.String)的varchar列或带有@Enumerated

的int列

B)

您可以尝试通过注释

指定枚举列
@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>

另见:

答案 1 :(得分:0)

通过将带有JPA注释和枚举类的类放入 domain-dir / lib / applib 目录中,可以解决这个问题。您必须将这些类放在 domain-dir / lib / applib 目录中的JAR中,然后使用{{1}使用asadmin在deploy命令上指定jar }。列出多个JAR文件时,请勿在逗号后面放置空格。

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

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

答案 2 :(得分:0)

我在一个项目上遇到了同样的问题,但是经过几次尝试,创建一个表来代替我的枚举更为合理。但是,似乎可以通过使用Jackson来工作