Sunday, January 5, 2014

Maven tips and tricks


Maven is cool. Reading the official tutorial on the Maven website, you get a pretty good idea what it does and how it works. The tutorial fails to tell you though the most important thing: follow the Maven conventions and it will work fine; if you don't follow them, Maven won't help, better forget about it.
One of the Maven conventions is the standard directory layout (read here). As long as your project's directory structure looks like in the following figure, using Maven is ok:






















Note that under the src/main you need to have your "java" directory for the java source code, "webapp" for the JSP/JSF pages (the eventual web application) and "resources" for some important files (read on, I'll give an example).

However, if you happen to develop a web application under Eclipse, your directory structure will be quite different:











Trying to use Maven now to build and deploy this Eclipse project is doomed to fail. The simplest solution to produce the war you need is to use Export from File menu under Eclipse and choose Web -> "WAR file".

For my own purposes I needed to use Maven, so I first moved the Eclipse project around in order to mimic the directory structure desired by Maven (as shown in the first figure above). From that point on, I learned some simple lessons:

1. as you've noticed, whenever you run a Maven phase/goal, Maven downloads all libraries necessary and places them under your local C:\Users\myUserName\.m2\repository; this is very powerful, as you can use Maven out of the box with a "tabula rasa" computer and end up with a neatly deployed project with all references solved

2. I wanted to add to my Maven project a dependency to an existing jar, so here it's what I've done:

   mvn install:install-file -DgroupId=com.mycompany.test -DartifactId=testid -Dversion=1.0 -Dpackaging=jar -Dfile=/path/to/jarfile/f.jar

This resulted in copying the desired dependency, f.jar, somewhere under .m2/repository.

I added then the following to my pom.xml:
<dependency>
     <groupId>com.mycompany.test</groupId>
     <artifactId>testid</artifactId>
     <version>1.0</version>
 </dependency>


3. by the way, while running mvn package you'll most likely get error messages referring to missing classes; to fix this, just look for the missing class online, e.g.:


Containing JAR files:

As you can see, findjar.com gives you links to Maven2 repositories. Following these links will tell you what artifactId and version you'll need to include in your pom.xml in order to fix this dependency.

Or even better, just go to the Central Maven Repository and look there for the missing class. Finally you'll get to the page that shows you exactly what you need to include in your pom.xml (you can copy-paste it):


















4. if you're using Hibernate (high likelihood I'd say), add your hibernate.cfg.xml to /src/main/resources; moreover, all other Hibernate configuration files, e.g. Patient.hbm.xml, must be added to the corresponding /resources subdirectory; I needed to add all my .hbm.xml files to /src/main/resources/model; after you run mvn package, they end up in the war file under WEB-INF\classes\model

5. since you're packaging a web application, add the following to your pom.xml:


 <build>  
    <plugins>  
     <plugin>  
      <groupId>org.apache.maven.plugins</groupId>  
      <artifactId>maven-war-plugin</artifactId>  
      <version>2.4</version>  
     </plugin>  
    </plugins>  
 </build>  

------------------

The following is the pom.xml file I'm using for my project:

 <project xmlns="http://maven.apache.org/POM/4.0.0"  

  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0  
            http://maven.apache.org/xsd/maven-4.0.0.xsd">  
  <modelVersion>4.0.0</modelVersion>  
  <groupId>com.mycompany.app</groupId>  
  <artifactId>app</artifactId>  
  <version>1.0-SNAPSHOT</version>  
  <packaging>war</packaging>  
  <dependencies>  
   <dependency>  
    <groupId>junit</groupId>  
    <artifactId>junit</artifactId>  
    <version>3.8.1</version>  
    <scope>test</scope>  
   </dependency>  
   <dependency>  
     <groupId>javax.servlet</groupId>  
     <artifactId>javax.servlet-api</artifactId>  
     <version>3.0.1</version>  
     <scope>provided</scope>  
   </dependency>  
   <dependency>  
     <groupId>org.hibernate</groupId>  
     <artifactId>hibernate-core</artifactId>  
     <version>3.6.3.Final</version>  
   </dependency>  
   <dependency>  
     <groupId>javax.faces</groupId>  
     <artifactId>jsf-api</artifactId>  
     <version>1.2_02</version>  
   </dependency>  
   <dependency>  
     <groupId>org.apache.openejb</groupId>  
     <artifactId>openejb-jee</artifactId>  
     <version>3.1.1</version>  
   </dependency>  
   <dependency>  
     <groupId>commons-logging</groupId>  
     <artifactId>commons-logging</artifactId>  
     <version>1.1.3</version>  
   </dependency>  
   <dependency>  
     <groupId>com.mycompany.test</groupId>  
     <artifactId>testid</artifactId>  
     <version>1.0</version>  
   </dependency>  
  </dependencies>  
  <build>  
    <plugins>  
     <plugin>  
      <groupId>org.apache.maven.plugins</groupId>  
      <artifactId>maven-war-plugin</artifactId>  
      <version>2.4</version>  
     </plugin>  
    </plugins>  
  </build>  
 </project>  


Enjoy Maven, folks !