Combining enum with EJB3 Entity bean

Do you recognize this: Although you are using a tool to develop your applications for some time, you are suddenly surprised by a certain error message you haven’t seen before? And you didn’t do anything different compared to the last time you used it.
Well, my experience is that in 100 times out of a 100, you did do something different. My last time in this situation was when I wanted to use a Java 1.5 enum type as a field in my EJB3 entity bean. I had done this before and at first sight everything looked well. Here was what I did:
Since I deploy my EJB3 application on JBoss 4.2.1 I supplied JBoss with the following Hibernate configuration file:

<?xml version="1.0" encoding="UTF-8"?>

<persistence xmlns="http://java.sun.com/xml/ns/persistence"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xsi:schemaLocation="http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd"
	version="1.0">
	<persistence-unit name="kpn-jf" transaction-type="JTA">
		<jta-data-source>java:/jdbc/my-datasource</jta-data-source>
		<properties>
			<property name="hibernate.dialect" value="org.hibernate.dialect.MySQLDialect"/>
			<property name="hibernate.max_fetch_depth" value="3" />
			<property name="hibernate.hbm2ddl.auto" value="create" />
			<property name="hibernate.show_sql" value="true" />
		</properties>
	</persistence-unit>
</persistence>

With this file the EJB container creates all database objects when I deploy my application (although this goes against everything I have learned as former ‘database’ developer I now just enjoy the simplicity of it).
The enum type I was using was defined as:

package net.pascalalma.domains;

public enum Gender {
		U, // Unknown
		M, // Male
		F  // Female
}

And the Entity Bean I was using:

@Entity
@Table(name = "CUSTOMERS")
@NamedQueries(value = { @NamedQuery(name = "findCustomerByCode", query = "SELECT o FROM Customers o WHERE code = :code") })
public class Customer
{
	private long id;
	private String code;
	private String initials;
	private String lastName;
	private Gender gender;

        ......

        @Column(name = "GENDER")
	public Gender getGender() {
		return gender;
	}
	......

Now, like I said before, at first there seemed nothing wrong with my application. I could run it and when I persisted Customers to the database I noticed rows were created in the database, so far so good. However, it went wrong as soon as I started to select an existing row and tried to make an Entity object of it. It was at this point I got the following stacktrace:

Caused by: java.lang.IllegalArgumentException: Unknown name value for enum class net.pascalalma.domains.Gender: 2
at org.hibernate.type.EnumType.nullSafeGet(EnumType.java:104)
at org.hibernate.type.CustomType.nullSafeGet(CustomType.java:105)
at org.hibernate.type.AbstractType.hydrate(AbstractType.java:81)
at org.hibernate.persister.entity.AbstractEntityPersister.hydrate(AbstractEntityPersister.java:2096)
at org.hibernate.loader.Loader.loadFromResultSet(Loader.java:1380)
at org.hibernate.loader.Loader.instanceNotYetLoaded(Loader.java:1308)
at org.hibernate.loader.Loader.getRow(Loader.java:1206)
at org.hibernate.loader.Loader.getRowFromResultSet(Loader.java:580)
at org.hibernate.loader.Loader.doQuery(Loader.java:701)
at org.hibernate.loader.Loader.doQueryAndInitializeNonLazyCollections(Loader.java:236)
at org.hibernate.loader.Loader.doList(Loader.java:2220)
at org.hibernate.loader.Loader.listIgnoreQueryCache(Loader.java:2104)
at org.hibernate.loader.Loader.list(Loader.java:2099)
at org.hibernate.loader.hql.QueryLoader.list(QueryLoader.java:378)
at org.hibernate.hql.ast.QueryTranslatorImpl.list(QueryTranslatorImpl.java:338)
at org.hibernate.engine.query.HQLQueryPlan.performList(HQLQueryPlan.java:172)
at org.hibernate.impl.SessionImpl.list(SessionImpl.java:1121)
at org.hibernate.impl.QueryImpl.list(QueryImpl.java:79)
at org.hibernate.ejb.QueryImpl.getSingleResult(QueryImpl.java:80)
at net.pascalalma.entities.Customer.findCustomerByCode(Customer.java:124)
at net.pascalalma.services.CustomerServiceBean.validateCustomer(CustomerServiceBean.java:114)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:585)
at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:112)
at org.jboss.ejb3.interceptor.InvocationContextImpl.proceed(InvocationContextImpl.java:166)
at org.jboss.ejb3.interceptor.EJB3InterceptorsInterceptor.invoke(EJB3InterceptorsInterceptor.java:63)
at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
at org.jboss.ejb3.entity.TransactionScopedEntityManagerInterceptor.invoke(TransactionScopedEntityManagerIntercep
tor.java:54)
at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
at org.jboss.ejb3.AllowedOperationsInterceptor.invoke(AllowedOperationsInterceptor.java:47)
at org.jboss.aop.joinpoint.MethodInvocation.invokeNext(MethodInvocation.java:101)
at org.jboss.aspects.tx.TxPolicy.invokeInOurTx(TxPolicy.java:79)
… 55 more
Caused by: java.lang.IllegalArgumentException: No enum const class net.pascalalma.domains.Gender.2
at java.lang.Enum.valueOf(Enum.java:192)
at org.hibernate.type.EnumType.nullSafeGet(EnumType.java:101)
… 88 more

Of course, my first reaction was WTF!?!?! This worked before and why doesn’t it work right now??
Well, as an experienced developer I knew there had to be something different with the last time I did this. So after a short investigation I found out that I had forgotten an annotation in my Entity bean when defining the Gender field as enum. After adding this:
@Enumerated(EnumType.STRING)
the value of the enum was stored as String, and could be used succesfully when constructing the Entity object.
So this gives ‘my mistake’ vs. ‘computer mistake’ 101 to 0…..

About Pascal Alma

Pascal is a senior IT consultant and has been working in IT since 1997. He is monitoring the latest development in new technologies (Mobile, Cloud, Big Data) closely and particularly interested in Java open source tool stacks, cloud related technologies like AWS and mobile development like building iOS apps with Swift. Specialties: Java/JEE/Spring Amazon AWS API/REST Big Data Continuous Delivery Swift/iOS
This entry was posted in EJB3, Hibernate and tagged , , . Bookmark the permalink.

2 Responses to Combining enum with EJB3 Entity bean

  1. jquest says:

    could you please provide the field definition that you used here. Hibernate complains that I have to use varchar(1) instead of char(1)

  2. Pascal Alma says:

    Well, Hibernate is allmost right. I have used, as field definition, varchar2(1).
    I was always told not to use ‘char’ in favourite of the ‘varchar2’ type, since its introduction by Oracle. So that’s why I left it out of the post.

Comments are closed.