When working on a Project, the last thing you need is to work with tools that you are not familiar with. In most cases, the project deadlines are very tight and this prevents you from spending time to learn new things and Maven (Homepage) is not an exception. While this can keep you away from Maven, or other tooling technologies, this article will show you the contrary. Maven is a good tool that, once understood, can help you save time even with simple projects.
This article assumes you have no knowledge about Maven or other build tools. While this is not a must, you should have a good understanding of software development lifecycle and what is required to build a Java application. This will help you understand better how Maven can assist you. In order to visualise some of the benefits, we will develop a small Java Swing application without using Maven and then with Maven. This is done for several reasons. One of the reasons is to show you how simple Maven is to use. More importantly, it will show how Maven can be used to carry out all the annoying and repetitive tasks and thus making you more productive.
All code listed below is available at: http://java-creed-examples.googlecode.com/svn/maven/Why should we use Maven/Simple Project Without Maven/ and http://java-creed-examples.googlecode.com/svn/maven/Why should we use Maven/Simple Project With Maven/. Most of the examples will not contain the whole code and may omit fragments which are not relevant to the example being discussed. The readers can download or view all code from the above link.
Let start by understanding what is Maven and what it can bring to the table.
When building software projects, you need to perform the following tasks irrespective of the development methodology used.
The above tasks are usually executed in the order listed above. For example, you cannot develop a solution before you analyse the requirements and design it. Some may argue that with the Test Driven Development (Book), the test cases are created before the solution is developed. While that is true, the tests are still executed after the development is done irrespective of when the tests were developed.
While all the thinking must be done by the team, the repetitive steps can be carried out by an assistant, if we may. The assistant is not intelligent but knows the software development flow and how to do basic things. For example, the assistant can create the projects based on templates, download required third party libraries (also known as JARs) and their dependencies too, build all components and create a deployable JAR, WAR or EAR file. Furthermore, the assistant can be empowered with new skills as the journey proceeds. This assistant is called Maven. This distinguishes Maven from other building tools such as Ant (Homepage) or other build scripts.
Before we dive in more detail about Maven, lets first create a simple project using only Spring Tool Suite (STS – Homepage).
To demonstrate the benefits of Maven, we will use a simple Java Swing application that requires the following:
The project consists of four classes:
We will start by first developing the project using just the IDE. We will go through all the steps required to meet the requirements listed above. Then we will rebuild the same project using Maven to illustrate how Maven can help.
The project starts as shown next.
The project shown above has two source folders one called src and the other one called test. Also, we have another folder with all third party libraries called lib. Our code depends on this library and without it, it will not compile. In order to simplify the processes we included the dependencies in the lib folder.
Let us start modifying the project to meet our requirements. We need to create a file called
MANIFEST.MF under the
META-INF folder and add the following entries:
Manifest-Version: 1.0 Main-Class: com.javacreed.examples.maven.wum.Main Class-Path: . lib/commons-lang3-3.0.jar SplashScreen-Image: images/Splash-Screen.png
The manifest file shown above takes care of three things.
Class-Path: . lib/commons-lang3-3.0.jar
Note that the
Class-Path starts with a
. (dot) and is followed by the relative path of the third party library: lib/commons-lang3-3.0.jar
Note that the manifest has an empty line at the end as shown below.
Testing this application is very simple. All we need to do is add the JUnit library through STS and then run the test code. The JUnit library can be added in four steps as shown next.
Now STS knows that it needs to use JUnit and it will make all necessary arrangements for that. We can now run the tests as shown below.
Running the actual tests is very straight forward. Simply run the project as JUnit Test. The tests should pass and the following output shown in the JUnit tab.
Note that the tests will not run automatically and you need to remember to run them whenever the code is modified. The application is now tested and ready to be deployed. All we need to do is to create a runnable JAR file that shows a splash-screen when starting. The following steps will guide us through.
This will open the export dialog.
Do not select the Runnable JAR file option as this will replace our manifest and will lose all changes. Furthermore, we cannot add a splash-screen through this option.
Make sure that the JAR file is exported to the same path where the lib directory is. The manifest refers to the third party libraries through a relative path.
This will produce our runnable JAR file in the provided path. The above steps need to be executed every time we need to create a runnable JAR. Furthermore, we need to update the manifest file whenever we need to use other third party libraries. Note that all efforts described here are not code related. We did not change any of the code. We simple tested it and created a runnable JAR.
We saw how to achieve our simple requirements without using Maven. In the next section we will do the same but only this time use Maven.
We will start of with the same project only the layout is slightly different to benefit from Maven’s default configuration and thus simplifying things further. With that said we can achieve the same results using the same layout by modifying Maven’s configuration.
Note that lib folder is missing as this is not required as Maven will manage all dependencies. In this simple example we only have one dependency that does not depend on anything else. In more complex projects, we may have dependencies that depend on other dependencies. We have to resolve all dependencies ourselves if we are to work without Maven.
Maven requires a configuration file per project called
pom.xml (Documentation). In this file we will enter all our configuration as shown next.
<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.javacreed.examples</groupId> <artifactId>why-should-we-use-Maven</artifactId> <name>Why should we use Maven?</name> <url>http://www.javacreed.com/why-should-we-use-maven/</url> <version>0.0.1-SNAPSHOT</version> <properties> <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> </properties> <build> <plugins> <plugin> <artifactId>maven-compiler-plugin</artifactId> <version>2.3.2</version> <configuration> <source>1.7</source> <target>1.7</target> </configuration> </plugin> <plugin> <artifactId>maven-assembly-plugin</artifactId> <configuration> <finalName>SimpleCalc</finalName> <appendAssemblyId>false</appendAssemblyId> <archive> <manifest> <addClasspath>true</addClasspath> <mainClass>com.javacreed.examples.maven.um.Main</mainClass> </manifest> <manifestEntries> <SplashScreen-Image>images/Splash-Screen.png</SplashScreen-Image> </manifestEntries> </archive> <descriptorRefs> <descriptorRef>jar-with-dependencies</descriptorRef> </descriptorRefs> </configuration> <executions> <execution> <id>make-my-jar-with-dependencies</id> <phase>package</phase> <goals> <goal>single</goal> </goals> </execution> </executions> </plugin> </plugins> </build> <dependencies> <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> <version>3.0</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.11</version> <scope>test</scope> </dependency> </dependencies> </project>
The pom file shown above may seem too complex but it is not as complex as one may think. The configuration file is XML based and thus it is quite verbose. Let’s break it in smaller pieces and go through the file piece by piece:
<plugin> <artifactId>maven-compiler-plugin</artifactId> <version>2.3.2</version> <configuration> <source>1.7</source> <target>1.7</target> </configuration> </plugin>
<plugin> <artifactId>maven-assembly-plugin</artifactId> <configuration> <finalName>SimpleCalc</finalName> <appendAssemblyId>false</appendAssemblyId> <archive> <manifest> <addClasspath>true</addClasspath> <mainClass>com.javacreed.examples.maven.um.Main</mainClass> </manifest> <manifestEntries> <SplashScreen-Image>images/Splash-Screen.png</SplashScreen-Image> </manifestEntries> </archive> <descriptorRefs> <descriptorRef>jar-with-dependencies</descriptorRef> </descriptorRefs> </configuration> <executions> <execution> <id>make-my-jar-with-dependencies</id> <phase>package</phase> <goals> <goal>single</goal> </goals> </execution> </executions> </plugin>
Furthermore, this plugin packs all dependencies as one JAR file. This means that we will end up with one JAR file and all dependencies code will be copied into this JAR file. Note that this may not work well with all projects and dependencies. If two different dependencies have entries with the same paths, then one will replace the other and may break the code.
<dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> <version>3.0</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.11</version> <scope>test</scope> </dependency>
With Maven we can test and deploy our program using Maven’s goals as shown next
This will open the edit configuration dialog.
and click the Run button.
Maven will do its magic and will test and produce our runnable JAR file. In just two steps we managed to test and create a runnable JAR file. Maven, using the configuration in the pom file, performed the following:
MANIFEST.MFfile with the correct entries
We can run this as many times as we need. Furthermore, STS provides a set of hotkeys:
X followed by
M. We do not have to provide the Maven goals the next time we run it as STS will remember them from our previous run.
Note that when using Maven, we did not prepare a MANIFEST.MF file. This is partially true as we instructed Maven to do it for us. If we require new dependencies (third party libraries), Maven will take all the necessary actions to include these in the deployed JAR file.
As you saw, all it takes are two steps to rebuild, test and produce a runnable JAR file using Maven when compared with the many steps we had to perform when we did not use Maven. In the next section we will see more about Maven and how we can benefit from using it.
Maven, different from other build tools, knows the software development life cycle. It knows that testing need to be executed after the code is compiled and not before. Test code and other third party libraries used only for testing are only required during testing and thus these should not be part of the final product and Maven leaves them out when packaging the application. Maven knows from where to download any third party libraries and their dependencies. Any third party libraries used needs to be also available at runtime. Maven provides several options how this can be achieved. As you can see from the pom file listed above, we did not tell Maven any of this. All we added were specific things required by our project, such as using a splash-screen.
When Maven is used for the first time, it downloads many plugins (Available Plugins) that it requires to perform the given tasks. This is because the default installation will only come with the bare minimum and everything else is downloaded as required. Anyone can contribute to make Maven better and more suitable for their needs through plugins. Plugins can be added as needed and projects configuration can be shared between multiple projects thus minimise the configuration required for each new project. Furthermore, there already exists a large number of Maven plugins for various tasks, such as packing an application into a single JAR file, database updates (Documentation) and deploying a Web application to a Tomcat server (Documentation) and many more.
Maven is a tool that can help in creating, building, publishing and managing dependencies for many applications. Maven is not bound to Java (Homepage) and it can be used with other programming languages such as PHP (Homepage). It is very easy to use and definitely worth its money (note that Maven is free) when compared with the time saved from doing the repetitive things ourselves.