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