86

I am writing a project for acceptance testing and for various reasons this is dependent on another project which is packaged as a WAR. I have managed to unpack the WAR using the maven-dependency-plugin, but I cannot get my project to include the unpacked WEB-INF/lib/*.jar and WEB-INF/classes/* to be included on the classpath so the build fails. Is there a way to include these files into the classpath, or is there a better way of depending on a WAR?

Many thanks.

Neeme Praks
  • 8,956
  • 5
  • 47
  • 47
deelo55
  • 1,161
  • 2
  • 12
  • 9

5 Answers5

122

There's another option since maven-war-plugin 2.1-alpha-2. In your WAR project:

<plugin>
    <artifactId>maven-war-plugin</artifactId>
    <version>2.1.1</version>
    <configuration>
        <attachClasses>true</attachClasses>
    </configuration>
</plugin>

This creates a classes artifact which you can use in the acceptance tests project with:

<dependency>
    <groupId>your-group-id</groupId>
    <artifactId>your-artifact-id</artifactId>
    <version>your-version</version>
    <classifier>classes</classifier>
</dependency>
Christoph Leiter
  • 9,147
  • 4
  • 29
  • 37
  • 6
    Only problem with this for me is that it doesn't pull in transitive dependencies – hertzsprung Nov 02 '12 at 17:31
  • 1
    Yeah, thanks for this hint :) It worked for me partially. With maven command line everything is ok. With maven in eclipse (m2e) build of tests referencing classes in the war is also ok, but when I try to run the tests (junit) I have to turn off m2e workspace resolution for that to work. Otherwise the junit run will throw a ClassNotFoundException for the referenced classes of the war. Somehow those are not included in the junit execution classpath though the war project is listed under the maven dependencies library in the project's build path. Any idea? – Gandalf Nov 07 '13 at 16:14
  • 1
    You can add the dependancy's pom as dependancy of the project to get transitive dependancies. So you get a dependancy on the classes and on on the pom – Jonatan Cloutier Feb 25 '15 at 20:38
  • Please note, that this plugin should go into the settings of the pom. – MichaelCleverly Mar 06 '15 at 14:05
  • In my case I needed the src/main/resources/* and they are also included in the "-classes.jar" - great! – Jonas Berlin Sep 24 '20 at 21:10
26

Indeed, by design, Maven doesn't resolve transitive dependencies of a war declared as dependency of a project. There is actually an issue about that, MNG-1991, but it won't be solved in Maven 2.x and I'm not sure that I don't know if overlays allow to workaround this issue. My understanding of the suggested solution is to duplicate the dependencies, for example in a project of type pom.


(EDIT: After some more digging, I found something interesting in this thread that I'm quoting below:

I have been helping out with the development of the AppFuse project over the last month where we make heavy use of the war overlay feature in the Maven war plugin. It is a really nifty feature!

To get max power with war overlays I have developed the Warpath plugin that allows projects to use war artifacts as fully fledged dependencies. In brief:

1) The contents of the /WEB-INF/classes directory in the war dependency artifacts can be included in the project's classpath for normal compile, etc tasks.
2) Transitive dependencies from the war dependency artifacts become available for use by other plugins, e.g. compile and ear - so no more having to include all the dependencies when creating skinny wars!

The plugin has now been actively used in the AppFuse project for the last few months, and I feel it is at a point where it is both usable and stable. Would the war plugin team be interested in including the warpath functionality inside the war plugin? It would seem to be the most natural place to host it.

So, I don't have any experience with it, but the maven warpath plugin actually looks nice and simple and is available in the central repo. To use it,include the following plugin configuration element in your pom.xml file:

[...]
<build>
  <plugins>
    <plugin>
      <groupId>org.appfuse</groupId>
      <artifactId>maven-warpath-plugin</artifactId>
      <version>1.0-SNAPSHOT</version>
      <extensions>true</extensions>
      <executions>
        <execution>
          <goals>
            <goal>add-classes</goal>
          </goals>
        </execution>
      </executions>
    </plugin>
  </plugins>
</build>
[...]

And add the war dependencies you want included in the classpath as warpath type dependencies:

[...]
<dependencies>
  <dependency>
    <groupId>org.appfuse</groupId>
    <artifactId>appfuse-web</artifactId>
    <version>2.0</version>
    <type>war</type>
  </dependency>
  <dependency>
    <groupId>org.appfuse</groupId>
    <artifactId>appfuse-web</artifactId>
    <version>2.0</version>
    <type>warpath</type>
  </dependency>
</dependencies>
[...]

Both the war and warpath dependency types are needed: the war type is used by the Maven war plugin to do the war overlay, the warpath type is used by the Warpath plugin to determine the correct list of artifacts for inclusion in the project classpath.

I'd give it a try.)

Pascal Thivent
  • 562,542
  • 136
  • 1,062
  • 1,124
  • 1
    Pascal, in my project I have separate modules for running integration test on different servers (each module for one server). These test modules have test classes and use dependency of war and overlays. I works great. – cetnar Nov 20 '09 at 15:07
  • Well, as I wrote, I was not sure, so thanks for that feedback, it's good to know. Can you just confirm it works with the transitive dependencies of a war and not only the java classes of the war? – Pascal Thivent Nov 20 '09 at 15:16
  • Ok, thanks. I see how it works now (the important part is your 2nd sentence: *your test project need to have also packaging war*). – Pascal Thivent Nov 20 '09 at 21:55
  • 1
    The problem I have with this plugin is that it's not supported by m2eclipse: http://maven.40175.n5.nabble.com/Dependency-with-war-type-td136645.html – milan Oct 21 '10 at 13:51
  • This plugin also breaks both the Maven release and assembly plugins because both of these will attempt to resolve the dependencies of a WAR that uses the warpath plugin, Maven will break saying it cannot resolve the type=warpath dependency. Too bad it doesn't work. – Dave Dec 12 '10 at 04:07
  • @PascalThivent: Do you happen to know if resolving transitive dependencies of a `war`/`ear` is controlled by Maven itself or by corresponding plugin? Is it possible to apply the same behaviour for `sar`? – dma_k Feb 07 '13 at 19:25
15

Use overlays. First, your test project need to have also packaging war.

Declare dependency of war project you want to test:

<dependency>
    <groupId>${project.groupId}</groupId>
    <artifactId>your-project-arftifactId</artifactId>
    <version>${project.version}</version>  
    <type>war</type>
    <scope>test</scope>
</dependency>

then configure maven-war-plugin overlay:

<plugins>
    <plugin>
        <groupId>org.apache.maven.plugins</groupId>
        <artifactId>maven-war-plugin</artifactId>
        <configuration>
            <webResources>
                <resource>
                    <directory>${basedir}/src/main/webresources</directory>
                    <filtering>true</filtering>
                </resource>
            </webResources>
            <overlays>
                <overlay/>
                <overlay>
                    <groupId>your.group</groupId>
                    <artifactId>your-project-artifactId</artifactId>
                </overlay>
            </overlays>
        </configuration>
    </plugin>

In the above example in test project I overwrite webresources configuration files (like conxtext etc.).

EDIT: This solution wasn't tested with Maven 3.

cetnar
  • 9,357
  • 2
  • 38
  • 45
  • 1
    I voted this down before I tested it. I don't know if this is because I am using Maven3, but indeed both my /classes and /lib folders are being transitively included through multiple WAR dependencies. Again -- sorry for voting it down. Apparently, this is the "correct" answer. – Dave Dec 12 '10 at 04:32
4

Good point, Justin. That got me actually solving my problem, namely: including a war into an assembly AND including all its transitive dependencies. I could not duplicate the war-dependency as 'jar' as you suggested since the assembly plugin would not find a jar referenced by that groupId/artefactId, but

  • duplicating the war-dependency as type pom

works! The war and its transitive dependencies are not included in the assembly. To exclude the (now also appearing) pom file I had to add an exclude element like this:

  <excludes>
    <exclude>*:pom</exclude>
  </excludes>

into my assembly.xml file.

I think this could also be a workaround for the original question of this thread.

Niels
  • 41
  • 2
-1

If you list the dependency on the war project as a jar dependency it seems to pickup the required jars/resources. I'm using Maven 2.2 + m2eclipse.

Justin
  • 4,437
  • 6
  • 32
  • 52