Monday, October 18, 2010

Maven and Hibernate hell.

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.


        
            org.hibernate
            hibernate-core
            3.6.0.CR2
        
        
            org.hibernate
            hibernate-annotations
            3.5.7-SNAPSHOT
        
        
            org.hibernate
            hibernate-commons-annotations
            3.3.0.ga
        
        
            org.hibernate
            hibernate-entitymanager
            3.6.0.CR2
        



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:


            org.hibernate
            hibernate-commons-annotations
            3.3.0.ga
            
                
                
                    org.hibernate
                    hibernate
                
            
        


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:


        
            org.hibernate
            hibernate-annotations
            3.5.7-SNAPSHOT
        
        
        
            org.hibernate
            hibernate-commons-annotations
            3.2.0.Final
        
        
            org.hibernate
            hibernate-entitymanager
            3.6.0.CR2
        

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?

Sunday, October 17, 2010

Maven: Add Mockito Dependency.

Adding Mockito dependency to your project is pretty simple.

Simply add the dependencies below to your pom.xml.

NOTE: You will need JUnit version 4.4 or earlier. I couldn't get Mockito to work with higher JUnit versions. Also, I did not try any prior version than Junit 4.4.


    org.mockito
    mockito-all
    1.8.5
    test
  

  
    junit
    junit
    4.4
    test
  


Update: I got Mockito 1.8.5 to work with JUnit 4.7. Not sure what changed.

Maven: Add Spring dependencies and Spring MVC your project

To enable Spring and Spring MVC modules in your maven project, follow the steps below

#1: Add Spring related dependencies. The dependencies below will get all the rest of the transitive dependencies.


  
    org.springframework
    spring-context
    ${org.springframework.version}

    
      
      
        commons-logging
        commons-logging
      
    

    
      
      org.springframework
      spring-webmvc
      ${org.springframework.version}
    


The org.springframework.version property is set to 3.0.3.RELEASE:

3.0.3.RELEASE

  

#2. Setup Dispatcher Servlet in your web.xml:

The Spring MVC requires setting the dispatcher servlet in web.xml. Below we are loading the /WEB-INF/sprin/app-config.xml (the main Spring application configuration file for the project) while instantiating the Dispatcher Servlet at application start up time i.e. when the server is starting up.

NOTE: You can name your application config with any name of your liking. Just make sure it is correctly referenced in Dispatcher Servlet setting in web.xml.


    springmvcdemo
    org.springframework.web.servlet.DispatcherServlet
    
      contextConfigLocation/WEB-INF/spring/app-config.xml
      
    1
  

  
    springmvcdemo
    /app/*
  


#3. The context config location points to the spring application config file for the application (app-config.xml). There are 2 things of note here:

a. The com.mayabansi.webappdemo will be scanned for classes annotated with @Controller, @Resources. @Component, @Service etc.

b. The mvc-config.xml, that holds the MVC configuration settings is imported.


    

    
    

#4. The MVC config file has Spring MVC related configuration settings:


    

    
    

    
    
        
        
    

Maven and Spring Enterprise Bundle Repository (in settings.xml)

There is this very informative article about Maven and adding Spring dependencies to your project here.

But I was not able to add the repositories below to my pom.xml and be able to connect with Enterprise Bundle Repository (EBR). I had to add them to my /home/rhasija/.m2/settings.xml file:

  
    SpringSource Enterprise Bundle Repository – External Bundle Milestones
    http://repository.springsource.com/maven/bundles/milestone
  

  
    SpringSource Enterprise Bundle Repository – SpringSource Bundle Releases
    http://repository.springsource.com/maven/bundles/release
  

  
    SpringSource Enterprise Bundle Repository – External Bundle Releases
    http://repository.springsource.com/maven/bundles/external
  


I am sure I must have done something wrong, but I prefer them to be in settings.xml anyway, instead of adding the above mentioned repositories to every project of mine.

Add hibernate related dependencies to pom.xml

To be able to use Hibernate in your project you need reference to Hibernate jars. Once you have set up your Maven to access JBoss repository for Hibernate artifacts, you can add the dependencies below to your pom.xml:

We have added:
#1. Hibernate annotations.
#2. Hibernate commons annotations.
#3. Hibernate entity manager.
#4. Hibernate validator.


  
    org.hibernate
    hibernate-annotations
    3.5.7-SNAPSHOT
  

  
  
    org.hibernate
    hibernate-commons-annotations
    3.2.0.Final    
  
  
    org.hibernate
    hibernate-entitymanager
    3.6.0.CR2
  

  
  
     javax.validation
     validation-api
     1.0.0.GA
  
  
    org.hibernate
    hibernate-validator
    4.0.2.GA
  

Maven: Add JBoss Maven repository as your alternate remote repository.

Hibernate publishes its artifacts to the JBoss Maven Repository under the org.hibernate groupId/namespace. To setup Maven to access JBoss Maven Repository follow the steps here. This will add the JBoss Maven Repository as an additional repository along with central maven repository.


#1. Create a file named 'settings.xml' in the '.m2' directory under your home directory. For me it is: /home/rhasija/.m2

And add the following content to it:

 


  
    

      jboss-public-repository
              
        
          jboss-public-repository-group
          JBoss Public Maven Repository Group
          https://repository.jboss.org/nexus/content/groups/public-jboss/
          default
          
            true
            never
          
          
            true
            never
          
        
      

      
        
          jboss-public-repository-group
          JBoss Public Maven Repository Group
          https://repository.jboss.org/nexus/content/groups/public-jboss/
          default
          
            true
            never
          
          
            true
            never
          
        
      

    
  

  
    jboss-public-repository
  

Maven: Make project IntelliJ Idea/Eclipse ready

With Maven it is pretty simple to make a project importable into IntelliJ Idea/Eclipse/Netbeans IDE. In this post I will cover IntelliJ Idea and Eclipse only.

For IntelliJ Idea: The easiest way is to choose: New Module -> Import Module from External Model and give it the project's root directory. But I believe this functionality has been recently added to IntelliJ Idea, which means it *might* not be available with pre Idea-X EAP. (I could be wrong here.)

UPDATE: As Hohonuuli pointed out in the comments, you can also do File -> Open Project, and select the pom.xml file in your project in Intellij (9 and 10).

For whom IntelliJ Idea does not provide this functionality based on the Idea version they are on, they can run a maven command to generate IntelliJ related files:

rhasija@rhasija-desktop $ mvn idea:idea

rhasija@rhasija-desktop $ ls -lart
total 72
drwxr-xr-x 3 rhasija rhasija  4096 2010-10-05 22:40 src
-rw-r--r-- 1 rhasija rhasija   791 2010-10-05 22:40 pom.xml
drwxr-xr-x 8 rhasija rhasija  4096 2010-10-05 22:49 ..
drwxr-xr-x 3 rhasija rhasija  4096 2010-10-05 22:50 target
-rw-r--r-- 1 rhasija rhasija 20933 2010-10-05 22:58 MavenSpringHibernateMockitoDemo.iws
-rw-r--r-- 1 rhasija rhasija  4535 2010-10-05 22:58 MavenSpringHibernateMockitoDemo.ipr
-rw-r--r-- 1 rhasija rhasija  3855 2010-10-05 22:58 MavenSpringHibernateMockitoDemo.iml
-rw-r--r-- 1 rhasija rhasija    47 2010-10-05 22:59 .gitignore
drwxr-xr-x 5 rhasija rhasija  4096 2010-10-05 22:59 .
drwxr-xr-x 8 rhasija rhasija  4096 2010-10-05 23:00 .git


Notice the MavenSpringHibernateMockitoDemo.iws, MavenSpringHibernateMockitoDemo.ipr, and MavenSpringHibernateMockitoDemo.iml files.

This will add Idea related files project.ipr, project.iws, and project.iml.

To make project Eclipse ready run the following maven command:

rhasija@rhasija-desktop $ mvn eclipse:eclipse

rhasija@rhasija-desktop $ ls -lart
total 32
drwxr-xr-x 3 rhasija rhasija 4096 2010-10-05 22:40 src
-rw-r--r-- 1 rhasija rhasija  791 2010-10-05 22:40 pom.xml
drwxr-xr-x 8 rhasija rhasija 4096 2010-10-05 22:49 ..
drwxr-xr-x 8 rhasija rhasija 4096 2010-10-05 22:50 .git
drwxr-xr-x 3 rhasija rhasija 4096 2010-10-05 22:50 target
-rw-r--r-- 1 rhasija rhasija  428 2010-10-05 22:50 .project
-rw-r--r-- 1 rhasija rhasija  317 2010-10-05 22:50 .classpath
drwxr-xr-x 5 rhasija rhasija 4096 2010-10-05 22:50 .


Notice the .project and .classpath files in the directory

GitHub: Add an existing project to GitHub

I have started using Git for personal projects and GitHub is a great source code repository for projects where Git is used as the SCS system.

In this installment I will cover adding an existing Git project to GitHub.

#1. Initialize the project as a Git project.

rhasija@rhasija $ git init
Initialized empty Git repository in /home/rhasija/workspace/blog_projects/MavenSpringHibernateMockitoDemo/.git/


#2. Add files to Git and check status of the current branch:

rhasija@rhasija-desktop $ git add src/* pom.xml 
rhasija@rhasija-desktop $ git status
# On branch master
#
# Initial commit
#
# Changes to be committed:
#   (use "git rm --cached ..." to unstage)
#
# new file:   pom.xml
# new file:   src/main/webapp/WEB-INF/web.xml
# new file:   src/main/webapp/index.jsp



#3. Commit the changes to the local repository:

rhasija@rhasija-desktop $ git commit -m "Initial commit with basic project structure."
[master (root-commit) f73707b] Initial commit with basic project structure.
 3 files changed, 33 insertions(+), 0 deletions(-)
 create mode 100644 pom.xml
 create mode 100644 src/main/webapp/WEB-INF/web.xml
 create mode 100644 src/main/webapp/index.jsp


#4. Give the remote repository location. In Subversion lingo remote here means the server where the project is stored.

rhasija@rhasija-desktop $ git remote add origin git@github.com:RaviH/MavenSpringHibernateMockito.git

Maven, Spring MVC, Hibernate and Mockito

In this 8 part series, I will cover how to create a simple Maven Web project, and then add Hibernate, Spring MVC and Mockito dependencies. I am assuming you have Maven installed. If not you can learn how to install Maven here.

First we will start with a brand new Maven project:

Step #1: Generate a Maven Webapp project:

mvn archetype:generate

The command above provides us a lot of archetype options. For this demo, we are going to choose #83 that is: maven-archetype-webapp (An archetype which contains a sample Maven Webapp project.).

Below (in bold) were the options I chose:

Choose a number: 80: 83
Choose version:
1: 1.0
2: 1.0-alpha-1
3: 1.0-alpha-2
4: 1.0-alpha-3
5: 1.0-alpha-4
Choose a number: : 5
Define value for property 'groupId': : com.mayabansi.webappdemo
Define value for property 'artifactId': : MavenSpringHibernateMockitoDemo
Define value for property 'version': 1.0-SNAPSHOT:
Define value for property 'package': com.mayabansi.webappdemo:

(NOTE: I have left out the rest of standard maven output for brevity)

Above command created the project structure below:

rhasija@rhasija-desktop ~/workspace/blog_projects/MavenSpringHibernateMockitoDemo $ find . 
.
./src
./src/main
./src/main/webapp
./src/main/webapp/index.jsp
./src/main/webapp/WEB-INF
./src/main/webapp/WEB-INF/web.xml
./src/main/resources
./pom.xml

rhasija@rhasija-desktop ~/workspace/blog_projects/MavenSpringHibernateMockitoDemo $ 

Step #2: Add basic project to source code control.

Step #3: Make project ready for IntelliJ Idea/Eclipse.

Step #4: Add JBoss Remote Repository as alternate remote repository for Hibernate artifacts.

Step #5: Add Hibernate related dependencies.

Step #6: Add Enterprise Bundle repository to settings.xml

Step #7: Add Spring MVC related dependencies.

Step #8: Add Mockito dependency.

NOTE: The example is complete. I will keep adding to it as I learn new things so as to make the example project richer.

The entire project can be downloaded from GitHub or you can use Git to checkout the project:

git clone git@github.com:RaviH/MavenSpringHibernateMockito.git