Dependency Hell or Including JSR303 into a hibernated JavaEE App

Today i integrated the JSR303 reference implementation, which is Hibernate-Validator 4.x, into an existing JavaEE application. The application is built on Spring 3.0 and uses our Synyx Hades project, which is also based on Spring, as an  OR-Mapper. (http://redmine.synyx.org/projects/show/hades)
First I just followed the Spring tutorial which is quite simple and straight forward. (http://static.springsource.org/spring/docs/3.0.x/spring-framework-reference/html/validation.html#validation-beanvalidation-spring)
After a redeploy and writing an example bean and a test for it, it was just disappointing because nothing worked and the stacktrace was not really helping at a first look.

testProperty(org.synyx.jsr303.validation.ValidatorTest)  Time elapsed: 0.002 sec  <<< ERROR!
java.lang.NoSuchMethodError: javax.persistence.Persistence.getPersistenceUtil()Ljavax/persistence/PersistenceUtil;
at org.hibernate.validator.engine.resolver.JPATraversableResolver.isReachable(JPATraversableResolver.java:33)
at org.hibernate.validator.engine.resolver.DefaultTraversableResolver.isReachable(DefaultTraversableResolver.java:112)
at org.hibernate.validator.engine.resolver.SingleThreadCachedTraversableResolver.isReachable(SingleThreadCachedTraversableResolver.java:47)
at org.hibernate.validator.engine.ValidatorImpl.isValidationRequired(ValidatorImpl.java:761)
at org.hibernate.validator.engine.ValidatorImpl.validatePropertyForGroup(ValidatorImpl.java:562)
at org.hibernate.validator.engine.ValidatorImpl.validateProperty(ValidatorImpl.java:496)
at org.hibernate.validator.engine.ValidatorImpl.validateProperty(ValidatorImpl.java:131)
at org.springframework.validation.beanvalidation.SpringValidatorAdapter.validateProperty(SpringValidatorAdapter.java:118)
at org.synyx.jsr303.validation.ValidatorTest.testProperty(ValidatorTest.java:64)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:74)
at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:82)
at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:72)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:240)
at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:180)
at org.apache.maven.surefire.junit4.JUnit4TestSet.execute(JUnit4TestSet.java:62)
at org.apache.maven.surefire.suite.AbstractDirectoryTestSuite.executeTestSet(AbstractDirectoryTestSuite.java:140)
at org.apache.maven.surefire.suite.AbstractDirectoryTestSuite.execute(AbstractDirectoryTestSuite.java:127)
at org.apache.maven.surefire.Surefire.run(Surefire.java:177)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.apache.maven.surefire.booter.SurefireBooter.runSuitesInProcess(SurefireBooter.java:345)
at org.apache.maven.surefire.booter.SurefireBooter.main(SurefireBooter.java:1009)

Why did I get an exception from a class called PersistenceUtil while just doing some validations via JSR303? Well, after reading the specification for JSR303 and some related blog entries, the solution is quite simple. JSR303 specification manifests, that if a class PersistenceUtil is in the classpath, the JPATraversalResolver has to be integrated into the validation as well. If afterwards the method getPersistenceUtil() is getting called, its obvious that this method is not available due to the fact that it is just a simple name matching.
Now I had THREE questions instead of one 🙂  :
* Why is there a class called PersistenceUtil in my classpath while I DON’T use any JPA2 library (And this class is only relevant for JPA2) – well this is surely just because the Hibernate guys had chosen the same name. Anyway, why the JPA2 guys used names like “PersistenceUtil” ????
* Why the specification manifests that if a class called PersistenceUtil is in classpath, there must be also a JPA validation?
* Why they do not additionally check against the needed method getPersistenceUtil() as well?
Anyway, as I needed a workaround, I checked the projects classpath… and I found my class PersistenceUtil but it was in a jar called “ejb3-persistence-1.0.1GA.jar” – don’t ask me, why there also is a class called PersistenceUtil (btw. I hate ANY classes with *UTIL* in its name). I googled around a bit and found more people, who had the same problem and the fix is really really easy. The guys who maintained the jar, fixed the problem due a little refactoring in version 1.0.2GA.
So the only thing to do was to update this dependency in pom.xml to 1.0.2GA and everything went fine… Took me three hours to find out 🙁

Kommentare

  1. Thanxx guyz....
    its working by changing the version of ejb3-persistance jar to 1.0.2

  2. Well this should be quite simple. Just replace the above mentioned Jars in your $EclipseProject/libs Folder.

  3. How would I fix the problem with plain old Eclipse or MyEclipse? I have not yet learned Maven
    Just ant and my automatic build in MyEclipse IDE. Can you help me understand better what you did to fix this problem?

  4. Fine if it helped! It's so annoying that Devs today uses classnames like this...

  5. Hmmm my pxo.xml tags where interpreted as XSS attack from your blog and were stripped :)
    Anyway I excluded from hibernate-entitymanager the ejb3-persistence because it downloaded the 1.0.1.GA and added
    ejb3-persistence in 1.0.2.GA as a dependency bellow :)

  6. Well I may say you saved lots of hours searching.
    Many thanks!
    I had to modify my pox.xml as follows
    org.hibernate
    hibernate-entitymanager
    3.3.2.GA
    ejb3-persistence
    org.hibernate
    org.hibernate
    ejb3-persistence
    1.0.2.GA
    pom
    compile