javahibernateclassloaderglassfish-4

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.


Solution

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