Log4J is a widely used logging library for Java. With the release of version 1.2.15, some dependencies were introduced that are not deemed necessary by some people [1]. The developers did not – for what ever reason – mark these dependencies as optional, even though they were not available in some common Maven repositories.

The following snippet demonstrates how to exclude transitive dependencies in Maven, applied to the case study of the transitive dependencies com.sun.jmdk:jmxtools and com.sun.jmx:jmxri.

<dependency>
  <groupId>log4j</groupId>
  <artifactId>log4j</artifactId>
  <version>1.2.15</version>
  <exclusions>
    <exclusion>
      <groupId>com.sun.jdmk</groupId>
      <artifactId>jmxtools</artifactId>
    </exclusion>
    <exclusion>
      <groupId>com.sun.jmx</groupId>
      <artifactId>jmxri</artifactId>
    </exclusion>
  </exclusions>
</dependency>

Links

  • [1] Mailing list entry stating that some dependencies are unnecessary
  • [2] Maven reference: Optional dependencies and exclusions

By default, Maven does not compile any debug information into an artifact. This is (sometimes) reasonable when you publish libraries which you do not want to reveal too much information about. For personal use, however, I prefer to be able to have a look at the full stack trace. Another benefit of adding debugging information is that you can read the original parameter names of methods.

As debug information is added at compile time, the Maven Compiler plugin is responsible for managing this kind of information:

<build>
  <plugins>
    <plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-compiler-plugin</artifactId>
      <version>2.0.2</version>
      <configuration>
        <!-- Necessary in order for the debug levels to be considered-->
        <debug>true</debug> 
        <debugLevel>lines,vars,source</debugLevel>
      </configuration>
    </plugin>
  </plugins>
</build>

Links

  • [1] Reference of Maven Compiler plugin

Depending on your version of Maven, the default Java version assumed by the compiler plugin may be quite old, even as old as not to recognize annotations. When working with annotations you will get compiler errors such as the following:

The method getProgress() of type TextFileReader must override a superclass method

Solution 1

You can configure Maven to accept (-source argument for the Java compiler) and produce byte code for (-target compiler argument) a certain Java version as follows:

<build>
  <plugins>
    <plugin>
      <groupId>org.apache.maven.plugins</groupId>
      <artifactId>maven-compiler-plugin</artifactId>
      <version>2.0.2</version>
      <configuration>
        <source>1.6</source>
        <target>1.6</target>
      </configuration>
    </plugin>
  </plugins>
</build>

Solution 2

It is even simpler to use properties:

<properties>
  <maven.compiler.source>1.6</maven.compiler.source>
  <maven.compiler.target>1.6</maven.compiler.target>
</properties>

Links

  • [1] Reference of Maven Compiler plugin

Maven-managed Eclipse projects generate appropriate project settings (classpath, build path, etc.) from the pom.xml. The following files need to be ignored in a Maven Eclipse project:

.settings
.project
.classpath
target/

As a shorthand, the following Bash command adds these lines to your .gitignore. It does not matter if your .gitignore is located in the project directory or in any parent of it.

echo “.settings
.project
.classpath
target/” >> .gitignore

Links

  • [1] gitignore man page

I ran across the use case described in the title when working with a legacy web application which also serves as a dependency for other (plugin) projects. To this end, besides the War file which is deployed as web application, I would like to have the contained Jar file being installed separately in my local repository.

This additional artifact can be obtained with a few lines in the pom.xml:

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-install-plugin</artifactId>
  <version>2.4</version>
  <executions>
      <execution>
          <phase>install</phase>
          <goals>
              <goal>install-file</goal>
          </goals>
          <configuration>
              <packaging>jar</packaging>
              <artifactId>${project.artifactId}</artifactId>
              <groupId>${project.groupId}</groupId>
              <version>${project.version}</version>
              <file>
                  ${project.build.directory}/${project.build.finalName}/WEB-INF/lib/${project.artifactId}-${project.version}.jar
              </file>
          </configuration>
      </execution>
  </executions>
</plugin>

This execution extracts the Jar file which is produced during the preparations of the War file and installs it with the project’s default group id, artifact id, and version.

Links

  • [1] Maven Install Plugin: install-file

By a “Maven web project” I mean a Maven project which has War packaging instead of Jar (in pom.xml: <project><packaging>war</packaging></project>). When importing such projects, Eclipse may not be able to figure out that the produced War artifact may be deployed on a server.

Maven may configure your Eclipse project to support WTP:

mvn -Dwtpversion=2.0 eclipse:eclipse

This goal can also be run inside Eclipse when you right-click the project and then select: Run as -> Maven build… As goal you type in eclipse:eclipse and add a new line in the parameter table where the parameter name is wtpversion and the value is 2.0.

Running the eclipse:eclipse goal for an existing project does not affect any unrelated settings in you project.

Links

  • [1] Maven eclipse plugin: WTP Support

Maven is not only great for dependency management, you can also download jars (which are called “artifacts” in Maven parlor) directly using the dependency:get goal.

The only thing you have to have in mind is the full artifact id which is easy to remember for prominent libraries such as the Apache Commons (org.apache.commons:commons-XX:VERSION) or Spring (org.springframework:spring-XX:VERSION).

As an example, the following command download the Apache Commons Math3 library (3.0) and stores it as /tmp/commons-math3.jar:

mvn org.apache.maven.plugins:maven-dependency-plugin:2.4:get 
   -Dartifact=org.apache.commons:commons-math3:3.0    
   -Ddest=/tmp/commons-math3.jar

Even though this one-lines seems to be simple, it took me some time to figure out how this command works:

  • Make sure you use the fully qualified plugin name and version 2.4. Otherwise the -Ddest parameter will not work.
  • The -Ddest parameter needs to be a filename, not a directory. The denoted file is overwritten in case of conflict.

Some Useful Artifacts to remember

If you want to look up the artifact id of an artifact then take a look at the Maven Central Search. Just some examples:

  • org.apache.commons:commons-math3:3.0
  • org.apache.commons:commons-io:1.3.2
  • junit:junit:4.10

Links

  • [1] dependency:get Reference
  • [2] Maven Central Search

If you have executions in your pom.xml which run during so-called interesting build phases. You need to provide a rule how m2eclipse shall deal with these executions (<execute/>,<ignore/>,<delegate/>).

The following snippet may be put into the pom.xml in order allow for the dependency plugin to run the goal build-classpath (Mind the <execute/> directive):

<build>
<pluginManagement>
  <plugins>
    <plugin>
      <groupId>org.eclipse.m2e</groupId>
      <artifactId>lifecycle-mapping</artifactId>
      <version>1.0.0</version>
      <configuration>
        <lifecycleMappingMetadata>
          <pluginExecutions>
            <pluginExecution>
              <pluginExecutionFilter>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-dependency-plugin</artifactId>
                <versionRange>[1.0.0,)</versionRange>
                <goals>
                  <goal>build-classpath</goal>
                </goals>
              </pluginExecutionFilter>
              <action>
                <execute/>
              </action>
            </pluginExecution>
          </pluginExecutions>
        </lifecycleMappingMetadata>
      </configuration>
    </plugin>
  </plugins>
</pluginManagement>
</build>

It is very(!) important to give a version range, otherwise a NullPointerException will be thrown.

Links

  • [1] Site on “M2E plugin execution not covered”
  • [2] List of “m2eclipse interesting build executions”

When moving a legacy project from Ant to Maven, I needed to change the default source (default: src/[main|test]/java) and resources (default: src/[main|test]/resources) directories in Maven. These settings may be configured in the <build> element of the project’s pom.xml.

  • <sourceDirectory> the directory where the sources of your application are stored
  • <testSourceDirectory> the directory where the sources of your test cases are stored
  • <resources> the resources of your main application
  • <testResources> the resources needed only by your test cases

The relevant part of the pom.xml in Maven 2.1.x and above looks like this (with default values):

<project>
  <!--[...]-->
  <build>
    <sourceDirectory>${project.basedir}/src/main/java</sourceDirect
    <testSourceDirectory>${project.basedir}/src/test/java</testSourceDirectory>    
    <resources>
      <resource>
        <directory>${project.basedir}/src/main/resources</directory>
      </resource>
    </resources>
    <testResources>
      <testResource>
        <directory>${project.basedir}/src/test/resources</directory>
      </testResource>
    </testResources>
    <!--[...]-->
  </build>
  <!--[...]-->
</project>

Links

When I update a Maven project in Eclipse Juno (m2eclipse version 1.2.0) I sometimes get back an error message reporting:

“Updating Maven Project”. Unsupported IClasspathEntry kind=4

There are some strategies on how to solve this. The most successful in my case is to perform the following steps:

  1. Disable the Maven Nature of the project by Right-clicking the project and selecting Maven -> Disable Maven Nature
  2. Fire up a terminal in the projects directory and run mvn eclipse:clean  (Important: the project still needs to be open in Eclipse!)
  3. Re-enable the Maven Nature of your project by Right-clicking the project and selecting Configure -> Convert to Maven Project

If you now update the project again (Right-click on project -> Maven -> Update Project), everything should run smoothly. If not, you may find additional hints in the stackoverflow question where I drew this solution from.

Alternative

Another successful solution to this problem is to open up the .classpath file of your project and remove all entries with attribute kind=”var”.

Links