An alternative Maven plugin for Ant and NetBeans
August 17, 2008 20 Comments
A while back I wrote a custom Maven plugin to “escape” from Maven because I personally prefer Ant for build scripting. I now generally use Maven only for JAR file dependency management and my plugin acts as a bridge between the Maven and Ant worlds. The plugin can automatically generate an Ant build.xml file from the Maven pom.xml file and it supports web-application (WAR) projects. A few people aware of the existence of this ‘underground’ plugin have been asking me for more details, and since I got a chance to tweak things recently, I’m putting down some information in this blog post on how to get the plugin and try it out. Maybe you will find it useful.
Some of the features the plugin provides are:
- Generated build file takes care of WAR packaging and deploying to Tomcat
- Once generated, Ant build is independent of Maven and offline
- Build file is IDE-independent, portable and includes targets for running JUnit tests as well
NetBeans users may find some of the advanced features interesting:
- Generation of the following different types of NetBeans projects:
- Java Free Form Project
- NetBeans ‘native’ Java SE Project
- NetBeans ‘native’ Java EE (web) project
- The Ant build (for Free Form project mode) is simple, human-readable and easily customizable instead of the horribly complex “build-impl.xml” that NetBeans users are familiar with
- In addition to the standard clean, compile, run actions etc., the generated Free Form project supports the following NetBeans-specific IDE-integration when a file is selected in the project explorer window:
- run single file
- debug single file
- run JUnit test for single file
- run JUnit test in debug mode for single file
- debug web application
- Hot Deploy single file into debug session
You just need the light-weight Java SE version of NetBeans in order to start and stop Tomcat, debug and even hot-deploy classes for your web-app. No extra plugins are required for e.g. Maven or Tomcat support. You can try this out for yourself by following the instructions below.
I’ll use the Wicket “quickstart” Maven Archetype as an example of how you can quickly get up and running using Ant on a Maven web-project. You need Maven 2 installed as a pre-requisite. The Wicket “quickstart” can be found here:
Open a command prompt, cut and paste the magic command and you get a simple web-application project along with a Maven POM definition, ideal for testing out the plugin features. This is the command I used for this example:
mvn archetype:create -DarchetypeGroupId=org.apache.wicket -DarchetypeArtifactId=wicket-archetype-quickstart -DarchetypeVersion=1.3.4 -DgroupId=com.mycompany -DartifactId=myproject
This will create a directory called “myproject” which contains a “pom.xml” file as well as some source code. We need to add a few lines to the pom.xml in order to use the custom plugin. First declare the repository for the plugin as follows by adding this snippet just above the <dependencies> section:
<pluginRepositories> <pluginRepository> <id>jtrac.info</id> <url>http://j-trac.sourceforge.net/repository</url> </pluginRepository> </pluginRepositories>
And within the <plugins> section, just add these four lines:
<plugin> <groupId>info.jtrac</groupId> <artifactId>maven-antprops-plugin</artifactId> </plugin>
That’s all that needs to be added to the POM, just 10 lines that don’t get in the way of any other Maven stuff you may want to do. To generate the Ant script, change to the newly created project folder and run the following command:
This will create a build.xml file and a “build-deps.properties” file. The properties file is a Plain Old Java Properties file that contains classpath information extracted from Maven as well as a list of dependencies with “runtime” scope which is used to create the “WEB-INF/lib” part of your WAR.
If you have Tomcat and Ant available on your system you can start Tomcat and deploy the WAR right away from the command line. But first you will need to point the build-file to where Tomcat is installed and this is a simple one-time matter of creating a “build.properties” file with a single line on it. Something like this:
From the command prompt, change to the “myproject” root directory (which should contain build.xml and build.properties by now) and type the following command:
Once Tomcat starts you should be able to verify that the app was successfully deployed by pointing your browser to: http://localhost:8080/myproject/
Eclipse users can use the “mvn eclipse:eclipse” command to open the project in Eclipse and start working with the Ant targets.
The command to create a NetBeans free-form project from the Maven POM is as follows:
This will create the “nbproject” folder and the NetBeans project file as well as an extra Ant script for NetBeans integration targets. Now you can open “myproject” as a NetBeans free-form project.
The “tomcat-start-debug” target is conveniently mapped to the NetBeans “run” IDE action, so just clicking on the big green “play” button should deploy the web-app running on Tomcat. If you right click on the project root “myproject” node, a “Stop Tomcat” context menu item should helpfully appear as well.
You can try the clean, compile, and war Ant targets etc. – which should work. The Wicket archetype includes a sample JUnit test also in “TestHomePage.java”. After clicking on this file to select it within the NetBeans project explorer window – go to the Run –> Run File –> Test “TestHomePage.java” toolbar menu (or hit CTRL + F6) and you should be able to run only the selected test. But it will fail now with a “java.lang.NoClassDefFoundError: javax/servlet/ServletException”.
This problem actually gives us a good example for demonstrating how the “build-deps.properties” file can be updated when dependencies change or are added to the POM. Now add the missing Servlet API dependency to the “pom.xml” file by adding this snippet within the <dependencies> section:
<dependency> <groupId>javax.servlet</groupId> <artifactId>servlet-api</artifactId> <version>2.4</version> <scope>provided</scope> </dependency>
Then re-run the command to generate build-deps.properties. Note that this command is designed so that if a “build.xml” file already exists, it will not be over-written.
Now run the test case again from NetBeans and it should pass. Unit testing a UI component is easy with Wicket!
One of the neat things about the Wicket archetype is that it embeds a Jetty web-app server using a small Java class called “Start.java” lying in the “test” source structure. The POM is already set with the right dependencies for Jetty and so you can simply right-click on this Java file within the NetBeans project explorer and choose “Run”. This will start a Jetty instance and deploy the WAR as well. You will be able to see the app running at http://localhost:8080/. Look ma, no Tomcat!
One more thing you can try is right-click on “Start.java” and do “Debug” instead of run. This will kick off a proper NetBeans debug session bringing up some sub-windows for viewing breakpoints, call stack etc. You can now try hot-deploying a single class without re-starting the app-server (Jetty). Try changing the text of the Label in HomePage.java to something else and saving the file. With the file selected in the NetBeans project window, look for the “Apply Code Changes” menu option – one place to find it is within the “Run” toolbar menu. A message should appear in the log saying that a class was reloaded. Refresh the browser and you should see the change in the text displayed.
Hot deploy should also work with Tomcat after initiating a debug-session (Attach Debugger) and then using the “Apply Code Changes” menu option.
The plugin is still experimental so if you find problems, do let me know in the comments. The commands for creating “native” NetBeans projects are “mvn antprops:nbjavase” and “mvn antprops:nbjavaee”. You need NetBeans with Java EE support to try the second option.
The plugin also should make it possible to package a project along with dependencies and hand-off to someone without Maven or internet access – but I haven’t completed this part yet.