I am a Maven newbie and wanted to setup an example Maven + Spring + Hibernate + Mockito project. I have been fairly successful at that but not without my struggles with Maven.
Here is my hibernate dependency structure in pom.xml. Some experienced maven and hibernate users probably would spot the mistake right away. Anyway, let me go on and fix the "errors" myself.
<!-- Hibernate Below is WRONG. Correct version is at the bottom of the page. -->
<dependency>
<groupid>org.hibernate</groupid>
<artifactid>hibernate-core</artifactid>
<version>3.6.0.CR2</version>
</dependency>
<dependency>
<groupid>org.hibernate</groupid>
<artifactid>hibernate-annotations</artifactid>
<version>3.5.7-SNAPSHOT</version>
</dependency>
<dependency>
<groupid>org.hibernate</groupid>
<artifactid>hibernate-commons-annotations</artifactid>
<version>3.3.0.ga</version>
</dependency>
<dependency>
<groupid>org.hibernate</groupid>
<artifactid>hibernate-entitymanager</artifactid>
<version>3.6.0.CR2</version>
</dependency>
Struggle #1: Maven and transitive dependencies.
I try to deploy my application in Tomcat and get the error below:
org.springframework.beans.factory.BeanCreationException:
Error creating bean with name 'sessionFactory' defined in ServletContext resource [/WEB-INF/spring/hibernate-config.xml]:
Invocation of init method failed; nested exception is java.lang.IncompatibleClassChangeError: Implementing class
After researching I found that the reason is multiple hibernate jars in the classpath. I check and yes there is a: hibernate.3.2.1.ga.jar and b: hibernate-core-3.6.0.CR2.jar. So now I have the task of finding out which hibernate dependency is bringing the 2 different hibernate jars.
On further research I find that hibernate-commons-annotation.3.3.0.ga.pom has dependency on hibernate.3.2.1.ga and hibernate-annotations-3.5.7-SNAPSHOT.pom has dependency on hibernate-core-3.6.0.CR2.
So that explains why I see two jars. I manually exclude the hibernate jar from hibernate-commons-annotations:
<dependency>
<groupid>org.hibernate</groupid>
<artifactid>hibernate-commons-annotations</artifactid>
<version>3.3.0.ga</version>
<exclusions>
<!-- Needed to exclude the hibernate core so it doesn't conflict with hibernate downloaded by hibernate-annotations dependency -->
<exclusion>
<groupid>org.hibernate</groupid>
<artifactid>hibernate</artifactid>
</exclusion>
</exclusions>
</dependency>
And that takes care of multiple hibernate jars on the classpath. Is there is an easy way to not have transitive dependency in maven?
Struggle #2: Now on deployment I get:
Caused by: java.lang.NoClassDefFoundError:
org/hibernate/annotations/common/reflection/MetadataProvider
hibernate-commons-annotation.3.3.0.ga.jar does not have MetadataProvider class. After googling the error I find: http://forum.springsource.org/showthread.php?t=89693
From hibernate-commons-annotation readme:
Version '3.3.0.ga' was a mistake during the release process, please disregard.
There is not such version 3.3.0.ga.
The solution then is to use hibernate-commons-3.2.0.Final
Final working dependency structure:
<!-- Hibernate -->
<dependency>
<groupid>org.hibernate</groupid>
<artifactid>hibernate-annotations</artifactid>
<version>3.5.7-SNAPSHOT</version>
</dependency>
<!-- NOTE: hibernate commons annotaions + Maven Hell: 3.3.0 version was wrong. -->
<dependency>
<groupid>org.hibernate</groupid>
<artifactid>hibernate-commons-annotations</artifactid>
<version>3.2.0.Final</version>
</dependency>
<dependency>
<groupid>org.hibernate</groupid>
<artifactid>hibernate-entitymanager</artifactid>
<version>3.6.0.CR2</version>
</dependency>
I wonder if all of this effort would have been saved had I just downloaded the jars from hibernate.org directly. Which makes me wonder if Maven is worth it for small projects?