Monday, December 23, 2013

Hibernate 4.2.8 , javassist 3.18.1 and ClassCastExceptions - watch out your classpath! #hibernate #jboss #javassist

I am writing this post as a tip and warning rather than an absolute solution. I will try to come back with a workaround for my case (WebSphere 8.5.5), but I am sure that other developers and applications  will be affected. I've lost some time trying to figure out the cause of the problem, so for the time being this post will help to increase the search index for the above keywords and link to the hibernate issue tracker.

In the current project I am working on, due to a bug in the Hibernate ORM version 4.2.0 library, I decided to move the library version forward on our setup and upgrade to the latest version. Hibernate currently features version 4.2.8 as the latest JPA 2.0 compliant version while 4.3.0 is the first official JPA 2.1 compliant. Since I am working on a Jee6 version, upgrading to 4.2.8 was my choice.

Eventually in 4.2.8 and onwards a 'serious' internal API change was implemented within the  library. Hibernate moved to a new version of javaassist, that introduces some new internal API calls and interfaces. See linked issue here. So, version 4.2.8 will fetch as a dependency javassist-3.18.1-GA to your app .

Eventually if you happen to introduce either
  • multiple dependencies to javassist versions 
  • a container is providing an older version through a 'parent' classloader for your ear/war
Then you will end up with problems like this. In plain words if by chance an older version of javassist is picked up by the active classloader in your container, while loading jpa entities or executing related code you will be most probably end up with weird class cast exceptions or 'class not found ' exceptions pointing to a deprecated javassist API.

IMHO, this change should have been introduced to a more 'major' version of Hibernate, but I trully understand that the development needs of the library sometimes can not be mandated by the different needs and setups of the worldwide developer user community. So this is just my opinion regarding the 'should have been', I still consider Hibernate the best Java ORM out there.

First actions in case you hit on this case:
  • Check your deployable, jar dependencies and find any other instances of the javassist especially older versions- check depending on your container and classloading settings how they are loaded.
  • In case you don't include explicitly any extra dependencies and the only instance is the one 'fetched from Hibernate' (like my case), then you need to examine if an older version of javassist is loaded from a application or server level shared library or from a 'shared' classloader in your application server. (I am still working on this one, for Websphere 8.5.5). You can experiment with shared library loading order or classloading mode (parent first/parent last)
  • If you can't find the solution based on the 2 above points or you tried to experiment with your class loading policy on your app and proved to be diasterous then, just switch to version 4.2.7 which seems to be the last one that is backwards compatible with older versions of javassist. 
If you are a JBoss EAP 6.2 and JBoss Wildfly 8 user, you are on the safe side, meaning these containers already ship with the 'latest' javassist version, but you still need to sort out any potential conflicting versions your application might introduce.

Hopefully I will come back with a workaround for my case. 

2 comments:

  1. Thanks a lot for the post. Exact issue I have. By any chance did u find any workaround?

    ReplyDelete