Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Parameter value did not match expected type

I have an enum with a list of states (e.g.)

enum State
{
   UP,
   DOWN,
   RETRY
};

The column in my database is of type enum. When I try to execute a Hibernate query by setting the parameter in the query using setParameter("keyword", State.RETRY);, I receive the error of

Parameter value [RETRY] did not match expected type [package.name.State (n/a)]

In my Glassfish 4.1 server.log for my domain. I am using Hibernate 4.3.6.

In looking at the source code for Hibernate, I see the error occurs because of lines 958-960 in org.hibernate.jpa.spi.BaseQueryImpl:

private static boolean isValidBindValue(Class expectedType, Object value, TemporalType temporalType) {
        if ( expectedType.isInstance( value ) ) {
            return true;
        }
...
return false;
}

isValidBindValue returns false and thus I get the message.

It prints out the String equivalent of the enum value because of this line:

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

The bind object is implicitly converted to the String value by calling the toString method on the Object which represents the enum State.RETRY.

So how I can I convince Hibernate that State.RETRY is an instance of State?

It looks like Hibernate updated to the JPA 2.1 spec which is more strict in this commit from April 2013:

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

The entity is annotated as follows:

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

Edit:

My RetryState enum is loaded by the EarLibClassLoader. Whereas Query is loaded by the URLClassLoader and the EntityManager is loaded by a different class loader.

like image 351
Engineer2021 Avatar asked Dec 23 '14 14:12

Engineer2021


2 Answers

I guess the main problem is that you are trying to use an enum datatype on the database side. This is not recommended because it often requires an proprietary enum type which may not be well supported by the JPA implementation (e.g. Hibernate). See this answer on a similar question for some details.

Further, with the annotation

@Enumerated(EnumType.String)

you are saying that you explicitly want, that the value is saved as a String in the database. I would expect that this fails if the real column type is some enum. Maybe the Hibernate code changes are trying to prevent these problems by forcing you to use either varchar or integer columns.

Possible solutions:

A)

Use a varchar column with @Enumerated(EnumType.String) or an int column with @Enumerated

B)

You can try to specify the enum column via the annotation

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

C)

You can try to specify your enum class via an hibernate XML mapping file:

<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>

See also:

  • JPA enumerated types mapping. Best approach
  • Enum in Hibernate, persisting as an enum
  • MySQL Enum performance advantage?
like image 161
unwichtich Avatar answered Nov 08 '22 23:11

unwichtich


This was fixed by placing the classes with the JPA annotations and enum classes into the domain-dir/lib/applib directory. You have to place these classes in a JAR in the domain-dir/lib/applib directory and then specify the jar on the deploy command with asadmin using the --libraries jar1,jar2,etc. Do not place a space after the comma when listing multiple JAR files.

Also, I had a common JAR that had EJB remote interfaces, so I had to break out my JPA classes into a new JAR and place them in my applibs directory also. I then put the JAR with the EJB remote interfaces into my EAR\lib directory.

The JARs in the lib/applibs directory are loaded by the URLClassLoader. The JARs in the EAR\lib are loaded by the EARLibClassLoader.

like image 31
Engineer2021 Avatar answered Nov 08 '22 22:11

Engineer2021