Showing posts with label Maven. Show all posts
Showing posts with label Maven. Show all posts

20 October 2012

Using the Maven 3 API with Maven 2 Components

Working on a Maven plugin, I was trying to upgrade the Maven API from 2.x to 3.0.4. After the upgrade, the plugin would no longer compile due to an unsatisfied transitive dependency of the maven-archiver used by the plugin: The class org.apache.maven.artifact.DependencyResolutionRequiredException could not be resolved.

The same issue was posted on the Maven Users list, but never answered.

Solution: Add a dependency on maven-core, or on maven-compat which should handle all compatibility issues with Maven 2.

08 August 2012

Maven Build Info for Web Applications

Problem

* You want to include build info like build number, revision number etc. as a web resource in your web applications.
* You have a multi-module Maven project with more than one WAR module and a number of JAR modules.
* You want to minimize copy-and-paste configuration in your POMs.
* The mechanism should not depend on a CI server.

Solution

This can be achieved using the Build Number Maven Plugin and the overlay feature of the Maven WAR plugin.

29 April 2012

Metamodel classes for OpenJPA with Maven, Eclipse and m2e

Metamodel classes are a not-so-well known feature of the JPA 2.0 standard. They allow you to write typesafe criteria queries using metamodel attributes instead of plain old strings to reference entity fields. (See this tutorial for some more background.)

Metamodel classes are generated by an annotation processor during the build process, but this is not enabled by default. OpenJPA logs a runtime warning when you build a criteria query and the metamodel classes cannot be found. So even if you don't use the metamodel, you may want to generate it just to get rid of this warning.

This article explains how to generate the metamodel both in Maven batch builds and in the Eclipse workspace.

15 April 2012

Multi-Instance Deployment from Eclipse to Tomcat

Problem

  • You are developing a web application for Tomcat in Eclipse.
  • You want to deploy multiple instances of the same application with different configurations directly from your workspace.
  • Of course, you don't want to duplicate any projects in your workspace.

Solution


This scenario can be solved quite easily with the vanilla Apache Tomcat adapter of Eclipse WTP. There is no need for any additional Eclipse plugins.

29 August 2011

Eclipse Maven Integration Extensions

For me, the most important new feature in Eclipse 3.7.0 (Indigo) is the improved Maven Integration, formerly developed by Sonatype under the name of m2eclipse, now an official Eclipse subproject under the name of m2e.

m2eclipse and Eclipse sometimes used to have different opinions on what was going on in the workspace, and so we had to go through series of refresh/update dependencies/update configuration/rebuild voodoo (or "m2eclipse dance" as some called it) to get projects in a good state. (Quote from the m2e Wiki).

m2e has a different approach. First of all, it complains when detecting a Maven plugin in one of your POMs that it cannot handle out of the box. m2e flags your POM with an error marker that will not go away until you tell m2e what do to about the unknown plugin. The easy way out is a Quick Fix to ignore the plugin, which means you'll have to run the corresponding Maven goal manually when you need it.

However, when the Maven plugin in question generates source code or post-processes byte code, this is usually not sufficient - ideally, Eclipse and m2e should pick up the required build steps from your POM automatically.

This issue is addressed by m2e extensions, which provide the missing link between Eclipse project builders and Maven plugins. An m2e extension for a given Maven plugin not only invokes the required mojos but also informs Eclipse about new source or binary folders created by the mojos, so that Eclipse and Maven can stay in sync.

My projects use a number of Maven plugins that are not supported by m2e out of the box, e.g. for JAXB and OpenJPA, so I started creating some custom extensions for these plugins, based on a GitHub fork of the official m2e extensions from Sonatype.

See the wiki page at GitHub for more details. The GitHub project also contains an Eclipse update site (aka p2 repository) for installing the plugins. Time permitting, I'll try to make these extensions available via the Eclipse marketplace.

For any fixes, additions or new extensions, feel free to send my pull requests.

20 March 2011

JAXB Marshalling with Custom Namespace Prefixes

The Problem


  • You have an XML schema with multiple XML namespaces.
  • You generate a JAXB model with xjc.
  • You build a JAXB document model and use the JAXB Marshaller to create XML from the model.
  • You want to override the default namespace prefixes ns1, ns2, ... created by the Marshaller.

07 February 2011

Maven Snapshot Repositories with Nexus

When you have a Maven build which depends on more than one external repository, it is usually a good idea to work with a repository manager. A repository manager also enables you to share your artifacts with other team members.

Nexus Open Source is probably the most popular Maven repository manager. Once it's set up correctly, it requires little or no maintenance, at least that's my experience after using it in different projects over the last three years.

I've just finished setting up Nexus for my current project, but this time, I spent almost a day chasing a problem related to snapshot repositories.

I had set up the Public Repositories group of Nexus as a mirror for Maven central and configured the Nexus Snapshots repository as an additional snapshot-enabled repository for the snapshots from my own project:

01 January 2011

Maven Plugin Inheritance

Writing Plugins for Maven is not hard, and Maven: The Complete Reference has an entire chapter on this subject. Of course, nothing is ever complete in real life or in software development, and one of the topics not covered in the book is plugin inheritance.

The scenario:
  • There is a (fictitious) maven-tea-plugin which takes a number of configuration parameters and has a tea goal. It is implemented by a TeaMojo.
  • You are writing a maven-greentea-plugin which has almost but not quite the same behaviour as the maven-tea-plugin. It takes the same parameters and has the same goals.
  • The natural idea is to derive a GreenTeaMojo from the TeaMojo and to override one or two methods of the base class, reusing all the parameters.
Unfortunately, this does not work, at least not out of the box. The problem is:
  • Maven uses poor man's Javadoc annotations to inject configuration parameters into Mojo classes.
  • This is still true in Maven 3.0, even though the traditional Plexus container has now been replaced by Guice.
  • The maven-plugin-plugin (i.e. the plugin responsible for plugin building) needs to scan the Mojo sources for Javadoc annotations, but the maven-tea-plugin sources are not visible during the build of the maven-greentea-plugin.
Now the maven-inherit-plugin from OPS4J fills the gap by looking up the plugin descriptor from the maven-tea-plugin and merging it with any additional parameters defined in the maven-greentea-plugin. To use it, just follow the documentation.

There is just one point to note: You have to add an @extendsPlugin annotation to your GreenTeaMojo to indicate the plugin you want to extend, but the value of this annotation is not quite obvious. It has to be either the plugin artifact id, or the plugin short name, tea in our case, but this requires the artifact id to be maven-tea-plugin or tea-maven-plugin.

26 July 2010

Building a Java EE 6 Web Application with Eclipse Helios, Maven and Glassfish

This is a short tutorial showing how to use Eclipse 3.6 (Helios) with Glassfish and Maven for building and running a Java EE 6 web application from a multi-module source tree.

We are going to import and run the Wicket gmap2-examples, demonstrating the use of Google Maps via Apache Wicket, but this is purely incidental - even if you prefer mainstream JSF or another web framework to Wicket, you may find this tutorial useful. There are absolutely no Wicket specifics involved; gmap2 was just a handy small but non-trivial example.

If you haven't worked with Maven before, you will get an idea how Maven can save you a lot of work managing the third-party dependencies of your project automatically.

This is what you'll see in the end:


There's quite a few things on your shopping list before you can start. If you are reading this, you probably already have the following on your disk:
You'll need to install these features into Eclipse:
  • Maven Integration for Eclipse (also known as m2eclipse)
  • Maven Integration for Eclipse (Extras)
  • Glassfish Java EE Application Server Plugin for Eclipse
Eclipse 3.6 has a new way of installing plugins via Help | Eclipse Marketplace. This is an integrated web client which lets you search for plugins by free text, so you no longer have to copy and paste update site URLs into the Update Manager - but you can still do so if you prefer.

The m2eclipse book has step-by-step instructions and screenshots explaining the installation process: start here with the m2eclipse installation. When you get to the Extras, the only ones required for the rest of this tutorial are Maven Integration for WTP and Maven SCM Integration. The WTP integration will let Eclipse recognize your Maven projects with war packaging as Dynamic Web Projects.

The Maven SCM Integration lets you fetch Maven projects directly from source code repositories like Subversion, Mercurial or others. Note that this integration simply invokes the corresponding command line clients like /usr/bin/svn.

Having installed m2clipse via the Eclipse Marketplace, use the same procedure to install the Glassfish Plugin.

After restarting Eclipse, set your Glassfish preferences via Window | Preferences | Glassfish Preferences. For this tutorial, you should check Start the Glassfish Enterprise Server in verbose mode and uncheck the other items.

Next, define a server runtime environment via Window | Preferences | Server | Runtime Environment | Add... Select the server type Glassfish | Glassfish Server Open Source Edition 3 (Java EE 6), check Create a new local server and click Next. Select your Glassfish installation directory - this is required to be the parent of the modules and domains directories, e.g. /home/hwellmann/glassfish-3.0.1/glassfishv3/glassfish. Click Next and fill in the domain name and the administrator credentials. If you did not change the Glassfish defaults, you can probably just click on Finish.

The Servers view has opened automatically. You can select your server and click on the Run button to  launch Glassfish from Eclipse. The Eclipse plugin launches Glassfish indirectly via an asadmin subprocess.

You will see some Glassfish log messages in the console. To stop Glassfish, do not hit the stop button in the Console view. This will just kill the asadmin process, but not Glassfish itself, and Eclipse and Glassfish will get terribly out of sync. Make sure to select the Servers view and hit the stop button there to avoid trouble.

Now for the interesting part: Let us import and build the gmap2 example project.

This project has a parent project with two subprojects, or modules in Maven terms. Maven requires you to store the module subprojects of a parent project in subdirectories of the parent directory. Eclipse normally cannot handle overlapping or nested directory structures for projects in the same workspace. Fortunately, m2eclipse works some magic to flatten the project structure, making Eclipse happy.

To import the example sources directly from the Subversion repository, select File | Import... | Maven | Check out Maven Projects from SCM and click Next. Fill in the SCM URL

https://wicket-stuff.svn.sourceforge.net/svnroot/wicket-stuff/tags/wicketstuff-core-1.4.9.2/gmap2-parent

and select the SCM provider svn, then click Next and Finish.

After a while, you will see three projects in your workspace:
  • gmap2
  • gmap2-examples
  • gmap2-parent

The parent project gmap2-parent has two subfolders gmap2 and gmap2-examples which are also represented as top-level Eclipse projects - this is a special feature of the m2eclipse integration.

The gmap2-examples subproject is a web application, as indicated by the Maven packaging type war. Using this and other information specified in the Maven POM, m2eclipse was able to turn this Eclipse project into a Dynamic Web Modules project - have a look at the Project Facets in the project properties to convince yourself.

Opening the project, you will notice two classpath containers Maven Dependencies and Web App Libraries. The latter contains just one item gmap2 with an open folder icon, indicating a reference to another subproject in our workspace that will go into WEB-INF/lib. The Maven Dependencies container displays all JARs required by our project, e.g. wicket-1.4.9.jar and slf4j-api-1.5.8.jar. All these were downloaded automatically by Maven into your local Maven repository on your hard drive, and m2eclipse makes Eclipse reference them from that location.

We are now ready to launch the web app: Select the gmap2-examples project folder and then Run As... | Run on Server from the context menu. Select the existing Glassfish server you created before and click Finish. After a while, you see the gmap2-examples welcome page in a web browser window.

Click on one of the links, e.g. marker listener, to see Google Maps in Firefox in Eclipse via Wicket on Glassfish on Java on Linux. (OK, maybe it's not Firefox or Linux on your machine...)

Note that the Java compilation and the WAR assembly and deployment were done by Eclipse, not by Maven.

However, you can also run a Maven build from Eclipse. To build our entire project hierarchy, select gmap2-parent and open Run As | Maven build... from the context menu. Enter the goals clean install and click Run. You will see the Maven messages in the console window. When Maven has finished, click Refresh (F5) on gmap2-parent, and open gmap2-examples/target to see the WAR file compiled by Maven.

09 May 2010

jeeunit: In-Container Integration Testing for Java EE 6

Recently, I've started working with Java EE 6 in general and Glassfish v3 in particular. Some software engineering best practices do not really depend on the framework or even the language you work with, so I was looking for a convenient way of doing automatic integration tests.

I've been in the habit of using JUnit not just for unit tests, but also for integration or system tests, so this was a natural starting point.

Traditionally, Java EE containers were heavy-weight machinery so that people preferred writing their tests to run out-of-container, paying the price of emulating or mocking some of the container functionality.

Maybe I've been looking in the wrong places, but most of the out-of-container testing approaches like ejb3unit seem to carry more baggage than the container itself, at least when it comes to working with Glassfish v3.

Anyway, as I could not find a ready-to-go solution, I wrote a little JUnit extension called jeeunit together with an example project showing how to set things up with Glassfish v3 and Maven.

The jeeunit project is available from Google Code under an Apache License.

23 February 2010

Setting up Eclipse for Roller

There is an Eclipse plug-in for almost any task, and most of them do their job rather nicely. On the other hand, even some of the more or less official ones may give you a hard time if you try to use them in combination.

Recently, I've been playing around with Apache Roller, a Java blog engine, much like Blogger or Wordpress. This project is currently in beta for the next major release 5.0, so I checked out the sources from trunk, ran the Maven build, created a PostgreSQL database and got my own blog engine up and running within minutes.

Some minor things did not quite work as expected, so I thought I'd just create an Eclipse workspace for Roller and build and run it from there. As it turned out, the combination of Maven, Subversion, and a Web Application was a rather fatal mix, and it took me a day to figure out what was going wrong.

Most of this was not a Roller issue at all: Eclipse Web application tooling (WTP) and Maven Integration (m2eclipse) just make too many implicit and conflicting assumptions which make it hard to set things up correctly, so this article is really about working with a mavenized web application in Eclipse, and Roller is just an example.

There are a couple of threads on the Roller developer mailing list dealing with Eclipse setups, but none of them really provides a working solution, so maybe this post can fill gap.

Step 1: Get Eclipse and all required plug-ins


To avoid any conflicts with other plug-ins or features not required for this project, I used a separate Eclipse installation consisting of
  • Eclipse for Java EE Developers 3.5.1
  • Subversive SVN Team Provider 0.7.8
  • Subversive SVN Connectors 2.2.1
  • Maven Integration for Eclipse 0.10.0
  • Maven Integration for WTP 0.10.0
Even if you do not intend to commit any changes from Eclipse, you will need the Subversion integration to deploy your web application from a Subversion working copy, otherwise Eclipse will try to pack the hidden .svn directories into the JARs and WARs and complain about duplicate paths.

Step 2: Set up m2eclipse

m2eclipse has a built-in pre-release version of Maven 3.0.0 which is not compatible with most existing projects based on Maven 2.x. Get a local installation of Maven 2.1.0 and define it as default for m2eclipse in Window | Preferences | Maven | Installations.

Step 3: Set up Tomcat

Download and install Tomcat 6.0.24 to a local directory. Create a Tomcat server instance for Eclipse via Window | Preferences | Server | Runtime Environments pointing to your Tomcat installation directory.

Install the additional prerequisites of Roller in the Tomcat lib directory:
  • mail.jar
  • activation.jar
  • your JDBC driver

Step 4: Get Roller into your Eclipse workspace

Create a new empty workspace and switch to the SVN Repository Exploring perspective. There is supposed to be an integration of m2eclipse and Subversive, which I never managed to get to work, so this is why I use the following somewhat clumsy procedure to populate my workspace:
  • Switch to the SVN Repository Exploring perspective and define a new repository location for https://svn.apache.org/repos/asf.
  • Check out Roller from roller/trunk. This will create a new project roller-project in your workspace.
  • Unfortunately, the Maven modules of this project do not yet appear as separate Eclipse projects. To change this, delete the project from your workspace and use File | Import | Maven | Existing Maven Projects. Select the workspace folder from your initial checkout.
  • After this, you should have six Maven projects in your workspace, all shared via Subversive.

Step 5: Apply some fixes in the workspace

  • Go to roller-weblogger-business and delete src/test/resources/org/apache/roller/weblogger/business/package.html, since this file would cause a clash with another copy from src/main/resources.
  • Open /roller-weblogger-web/src/main/webapp/WEB-INF/security.xml and replace spring-security-2.0.1-openidfix.xsd by spring-security-2.0.4.xsd.
  • Copy your roller-custom.properties to /roller-weblogger-web/src/main/resources.

Step 6: Configure your web application

  • Open the project properties of roller-weblogger-web.
  • Select the Java EE Module Dependencies and activate roller-planet-business, roller-core and roller-weblogger-business.
  • Make sure that the resources from all dependent projects will get copied into the web application by modifying the build path settings of roller-planet-business, roller-weblogger-business and roller-weblogger-web. Select Java Build Path from the project properties and remove the Excluded: ** entry from src/main/resources for each of these projects.

Step 7: Run a Maven build

  • Select roller-project/pom.xml. From the context menu, select Run As | Maven build...
  • In the launcher dialog, fill in the goals clean install and (optionally) check Skip Tests to save some time during each build.
  • When the build has completed, select all projects and press F5 so that Eclipse will see all the resources created by Maven.
  • This step is required, since the Maven build generates some additional resources and runs the OpenJPA Enhancer. These two steps would not be handled by the Eclipse automatic build.

Step 8: Make sure that Eclipse picks up the generated resources

  • Create a folder /roller-weblogger-web/src/main/sql and turn it into a source folder.
  • Copy /roller-weblogger-business/target/dbscripts into this folder.

Step 9: Get Rolling!

  • Select roller-weblogger-web and invoke Run As | Run on Server from the context menu.
  • Select the Tomcat instance created in Step 3 and activate it as default if you like and click Finish.

Troubleshooting

  • If you get stuck, clean the Tomcat instance. Open the Servers view and select Tomcat. From the context menu, invoke Clean...
  • To check the web application assembled by Eclipse, have a look into <Eclipse workspace>/.metadata/.plugins/org.eclipse.wst.server.core/tmp0/wtpwebapps/roller-weblogger-web/
All of this should have been a lot easier. m2eclipse will have to mature, and Eclipse should be more flexible about resource locations...

    29 March 2009

    Maven Plugin for Eclipse Source Bundles

    The Maven Source Plugin creates a JAR containing the sources of a project and attaches it to the main artifact of the project.

    It would be nice if you could directly use this JAR as source attachment for a bundle in your Eclipse target platform, but Eclipse 3.4 expects a special Source Bundle format with specific headers in the manifest. There is a feature request to support this directly in the Maven Source Plugin.

    To fill this gap, I had a look at the sources of the Maven Source and Archiver plugins and wrote my own maven-sourcebundle-plugin. This plugin is available for public use as a subproject of the DataScript project hosted at BerliOS.

    There is no public Maven repository for this project yet, but it is contained in the latest binary release rds-bin-0.30, or you can get the sources from Subversion.