Why is Maven including multiple versions of the same dependency? - java

I have a Maven java web app (.WAR) project that includes several libraries, including the Wicket libraries (but I don't think the problem is wicket itself, but rather with maven).
Here's the problem: even tho I only include Wicket 6.20.0, the resulting .WAR contains two copies of the Wicket libraries: 6.20.0 and 6.18.0, as you can see in this screenshot:
Thinking of some conflicting imports I printed the dependency tree using the:
mvn dependency:tree
commnad... but there is no mention of Wicket 6.18.0 in the dependency tree! I also double-checked using Eclipse's "dependency hierarchy" view and I can confirm there's no trace of that import.
I even did a search for string "6.18.0" across the entire workspace with Eclipse, but it's nowhere to be found!
How can I find out what is causing the inclusion of that duplicate version of the library?

Maven doesn't work in this way.
The resolution of more than one dependency with the same artifactId and groupId but with a different version will result to a single dependency (the version used is no determinist).
The presence of two artifacts with the same artifactId and groupId but with two distinct versions in a same lib folder of the WAR is probably related to one of these :
you don't execute mvn clean package but only mvn package.
your use a bugged version of the Maven war plugin. Try to update it to check that.
you have a Maven plugin that copies Wicket jars 6.18.0 in the WEB-INF/lib folder of the target folder during the build of the component.
the maven WAR project you are building has as dependency an artifact of type WAR. In this case, the dependencies of the WAR dependency are so overlaid in the WAR project that you are building.
An interesting Maven issue about duplicated JAR because of WAR dependencies :
JARs with different versions can be in WEB-INF/lib with war as dependencies
Your answer and your comment indicate that actually you have a WAR dependency in your build.
Unfortunately, there is not really a good and long term effective solution to bypass this limitation.
As said in my comment, using the packagingExcludes property of the maven war plugin is a valid workaround for the actual issue :
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.4</version>
<configuration>
<!-- ... -->
<packagingExcludes>WEB-INF/lib/wicket-*-6.18.0.jar</packagingExcludes>
</configuration>
</plugin>
But beware, using that will do your build less robust through the time.
The day where you update the version of the WAR dependency and that in its new version, it pulls again a different version of wicket, you have still a risk to have duplicate jars with two distinct versions in your built WAR.
Using the overlay feature by specifying the overlay element of the maven-war-plugin is generally better as it focuses on the overlay applied for the war dependency. It fixes the problem early.
As a result, you could define to exclude any wicket JARs from the WAR dependency :
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<version>2.4</version>
<artifactId>maven-war-plugin</artifactId>
<configuration>
<overlays>
<overlay>
<groupId>com.whatever.youlike</groupId>
<artifactId>myArtifact</artifactId>
<excludes>
<exclude>WEB-INF/lib/wicket-*.jar</exclude>
</excludes>
</overlay>
</overlays>
</configuration>
</plugin>
This way is better but this is still a workaround.
The day where the dependency WAR is updated and that it pulls new dependencies (other than Wicket) that are declared in your actual build but with different versions, you may finish with the same kind of issue.
I think that declaring a dependency on a WAR artifact should be done only as we don't have choice.
As poms and projects refactoring are possible, introducing a common JAR dependency which the two WARs depend on and that contains only common sources and resources for the two WARs makes really things simpler.

Well, I figured it out while poking around.
I had a dependency of type "war" in the project:
<dependency>
<groupId>com.whatever.youlike</groupId>
<artifactId>myArtifact</artifactId>
<version>1.0.7-SNAPSHOT</version>
<type>war</type>
</dependency>
Apparently (I wasn't aware of this, my fault here) these type of dependencies will include themselves in the classpath by copying all libs to the main WAR /libs folder, but these will NOT show app in the dependency tree / dependency hierarchy.
I solved by configuring an explicit exclusion in the WAR plugin:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.4</version>
<configuration>
<!-- ... -->
<packagingExcludes>WEB-INF/lib/wicket-*-6.18.0.jar</packagingExcludes>
</configuration>
</plugin>

Use clean install and the double dependency will probably be gone.

Because other libs can use same libs but different version or you tried different version and didn't make mvn clean

The command mvn dependency:tree is telling you the correct information - what you are looking at here is an eclipse / build issue.
Clear out all the target and build areas in your project. If need be, check it out from source control to a new folder.
Alternatively you can build your project in IntelliJ IDEA, and see if you get the correct dependencies (most likely you will).

Related

Configure maven plugin version without changing pom.xml manually

Problem Description
I'm working with a collection of old projects from defects4j. My problem now is that since I want to combine those projects with a newer maven plugin, a regression test tool, there are some issue with the maven surefire plugin version.
In the pom.xml that come along with the projects, there are no specifications of surefire version:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<executions>
<execution>
<id>plain</id>
<configuration>
<includes>
<include>**/*Test.java</include>
</includes>
<runOrder>random</runOrder>
</configuration>
</execution>
</executions>
</plugin>
However, the regression tool (made into a maven plugin), require surefire version of 2.14 and above. So I get error like this:
[ERROR] Failed to execute goal edu.illinois:starts-maven-plugin:1.4-SNAPSHOT:select (default-cli) on project commons-lang: Unsupported Surefire version: 2.12.4. Use version 2.13 and above
Efforts Done
I checked several stackoverflow posts, and they talked about the effective pom. When I run mvn help:effective-pom, I can see that the version of surefire used is
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<version>2.12.4</version>
Question
Since the project collection in defects4j does not specify surefire version in their pom.xml, is there a way to specify the surefire version used to 2.14 or above from command line? I want to prevent from manually editing the pom every time.
Update
by running mvn dependency:resolve-plugins, i get
Plugin Resolved: maven-surefire-plugin-2.12.4.jar
So it seems to me that somehow maven use 2.12.4 as a default. The reason maybe that I used this version previously. How do I fix this?
Without modifying the pom manually?
Any advice will be welcomed!
Update:
Problem solved by editing maven's super pom.
Maven takes the newest version from the repository if there was no version fixed in your POM, parent POM or the super POM (from which every Maven project inherits).
It is best practise to fix a version "manually" in the POM. The best place for this is a parent POM from which the projects inherit (this means, only one place to change).
You cannot just supply a version from command line. Unless you do some tricks like putting <version>${surefire.version}</version> into the plugin definition and set this property from command line.
I'm 4+ years removed from working with poms so don't remember everything, but consider a couple of things.
First, since the pom you show isn't specifying the version of surefire to use I don't think that the 2.12.4 version can be coming from that directly. Try getting a dependency tree to see where things are coming from. Try How can you display the Maven dependency tree for the *plugins* in your project? for that and a few other suggestions.
Second, I think I recall that in your own pom you should be able to specify the version of plugin to associate with a dependency that doesn't specify one. You'll have to research that option yourself.
I think your best bet is the dependency tree to find what's using what and where things are coming from. If you get the tree and still can't figure out what to do try adding the tree output to your question. (You can edit out parts that are proprietary, or clearly unrelated.)

Maven Shade - add local JAR file [duplicate]

I already found an answer here on Stack Overflow how to include a 3rd party JAR in a project without installing it to a "local repository":
Can I add jars to maven 2 build classpath without installing them?
But, when I use the Maven Shade Plugin to create a JAR that includes all the dependencies of the project as well, the 3rd party JAR is not included automatically.
How can I make the Maven Shade Plugin add such a 3rd party JAR in to the shaded JAR?
As per the answer gotten, I made it work. What I did was, added this snippet to the beginning of my pom.xml:
<repositories>
<repository>
<id>repo</id>
<url>file://${basedir}/repo</url>
</repository>
</repositories>
Then added a dependency for my project, also to pom.xml:
<dependencies>
<dependency>
<groupId>dummy</groupId>
<artifactId>dummy</artifactId>
<version>0.0.0</version>
<scope>compile</scope>
</dependency>
</dependencies>
And then ran a command line to add a package to 'repo':
mvn org.apache.maven.plugins:maven-install-plugin:2.3.1:install-file
-Dfile=<my-jar>.jar -DgroupId=dummy -DartifactId=dummy
-Dversion=0.0.0 -Dpackaging=jar -DlocalRepositoryPath=`pwd`/repo/
(Not sure if the repo path needs to be a full path, but didn't want to take chances.)
The contents of the repo subdirectory is now:
repo/dummy/dummy/0.0.0/dummy-0.0.0.jar
repo/dummy/dummy/0.0.0/dummy-0.0.0.pom
repo/dummy/dummy/maven-metadata-local.xml
Now I can check this in to version control, and have no local or remote dependencies.
But, when I use the Maven Shade Plugin to create a JAR that includes all the dependencies of the project as well, the 3rd party JAR is not included automatically.
Yes, because the system scoped dependencies are assumed to be always present (this is exactly what the system scope is about) so they won't be included. People actually don't understand what system scope dependencies are, they just keep abusing them (yes, this is abuse), and then get side effects and wonder why (as Brian pointed out in his answer).
I already wrote many, many, really many times about this here on SO and in 99% of the cases, system scoped dependencies should be avoided. And I'll repeat what the Dependency Scopes mini guide says one more time:
system: This dependency is required in some phase of your project's lifecycle, but is system-specific. Use of this scope is discouraged: This is considered an "advanced" kind of feature and should only be used when you truly understand all the ramifications of its use, which can be extremely hard if not actually impossible to quantify. This scope by definition renders your build non-portable. It may be necessary in certain edge cases. The system scope includes the <systemPath> element which points to the physical location of this dependency on the local machine. It is thus used to refer to some artifact expected to be present on the given local machine an not in a repository; and whose path may vary machine-to-machine. The systemPath element can refer to environment variables in its path: ${JAVA_HOME} for instance.
So, instead of using the system scope, either:
Add your libraries to your local repository via install:install-file. This is a quick and dirty way to get things working, it might be an option if you're alone but it makes your build non portable.
Install and run an "enterprise repository" like Nexus, Archiva, or Artifactory and add your libraries via deploy:deploy-file. This is the ideal scenario.
Setup a file based repository as described in this previous answer and put your libraries in there. This is the best compromise if you don't have a corporate repository but need to work as a team and don't want to sacrifice portability.
Please, stop using the system scope.
The Maven addjars plugin solves this problem - see
http://code.google.com/p/addjars-maven-plugin/wiki/UsagePage
Used <resources> to include my lib with all jars. i.e:
<build>
<resources>
<resource>
<directory>${project.basedir}</directory>
<includes>
<include>lib/*.jar</include>
</includes>
</resource>
</resources>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.3</version>
<configuration>
<createDependencyReducedPom>false</createDependencyReducedPom>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
If you only need a quick and dirty solution, you can add the content of the extracted jar file to your src/main/resource directory.

How do I create an Eclipse plugin release using Maven and Tycho?

I am building an Eclipse project that consists of a number of plug-ins that are packed together. I have create POM files for each component and a main POM for the project. Something like this:
projectDir\releng\pom.xml <-- Parent project
projectDir\proj1\pom.xml <-- Child project 1
projectDir\proj2\pom.xml <-- Child project 2
My build currently works by calling the parent POM which builds everything. Until now I have been building using 0.0.1-SNAPSHOT as the version of the parent POM, and in each Eclipse plug-in I have 0.0.1.qualifier as the version in the MANIFEST.MF file.
I now want to promote my latest version to 0.1.0. From my understanding, this means that I have to go over ALL of my POM files AND MANIFEST.MF files and upgrade the version in both of them (since while the version is defined in the parent POM, it is referenced in all child POM:s).
Is this the correct way to do this or is there a way to automate the whole process and not make mistakes?
P.S. There is the Maven Release plugin but this won't work with Eclipse.
For the version update step of a relase process, there is the tycho-versions-plugin which knows how to consistently update the POMs and manifests.
Just go to the root of your parent/aggregator module and call
mvn org.eclipse.tycho:tycho-versions-plugin:set-version -DnewVersion="0.1.0"
This will update the version of the parent project and of all child projects with the same/equivalent version as the parent project. In your case, these are all projects because the Eclipse versions 0.0.1.qualifier is considerered equivalent to 0.0.1-SNAPSHOT in Tycho.
For the remaining steps of the release process (tagging, building, pushing tags, etc.) just call the appropriate SCM or Maven commands, e.g. from a script. I haven't tried to use the maven-release-plugin for this (and apparently no-one else has).
Please have a look here: Unleash Maven Plugin - Tycho Releases
The Unleash Maven Plugin is implemented as an alternative to the Maven Release Plugin and has a Tycho feature which should do exactly what you need. Furhtermore it is much more flexible, failure tolerant and has an integrated rollback feature.
I will publish some blog posts soon to promote and explain this plugin.
just some hints on how we implemented it.
It can be done with an extra plugin that does transformation of versions in MANIFEST.MF and *.product files. This plugin needs to be a lifecycle participant. #Component(role = AbstractMavenLifecycleParticipant.class) the reason for this is that is must transform and commit before the release plugin starts to look for modifications. Then it must also to transformation back after the release.
The mojo executor plugin saves a good deal of work since it can call the replacer, buildhelper and scm plugin from inside your plugin.
Another important gotcha is that you need to disable to hard coded clean invocation that tycho does by confguring the release plugin to configure the clean plugin to skip execution.
Hope this helps.
There is a new feature in tycho-1.1.0 (unreleased at the time of this post) that should support what you're trying to do.
If you've configured your pom correctly for standard maven-release + added the dep to tycho 1.1.0, you can customize your build as follows [1]:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-release-plugin</artifactId>
<version>2.5.3</version>
<configuration>
<preparationGoals>org.eclipse.tycho:tycho-versions-plugin:${tycho-version}:update-eclipse-metadata org.apache.maven.plugins:maven-scm-plugin:1.9.5:add org.apache.maven.plugins:maven-scm-plugin:1.9.5:checkin</preparationGoals>
<completionGoals>org.eclipse.tycho:tycho-versions-plugin:${tycho-version}:update-eclipse-metadata org.apache.maven.plugins:maven-scm-plugin:1.9.5:add org.apache.maven.plugins:maven-scm-plugin:1.9.5:checkin</completionGoals>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-scm-plugin</artifactId>
<executions>
<execution>
<id>default-cli</id>
<goals>
<goal>add</goal>
<goal>checkin</goal>
</goals>
<configuration>
<includes>**/META-INF/MANIFEST.MF, **/feature.xml, **/*.product</includes>
<excludes>**/target/**</excludes>
<message>Changing the Eclipse files versions</message>
</configuration>
</execution>
</executions>
</plugin>
[1] This is taken directly from a tutorial that describes this new feature:
https://wiki.eclipse.org/Tycho/Release_Workflow

Only include jar in gwt compile and not in WEB-INF/lib

I'm wanting to use the slf4j-gwt library https://github.com/FinamTrade/slf4j-gwt
But I only want to include it in my gwt compile, not in the war that is built as I'm having issues with tomcat startup calling GWT.create...
Is there a simple way to do this? I would expect the maven gwt compiler plugin to support this but I can't see that it does.
<scope>provided</scope> or <optional>true</optional>.
Neither one is semantically satisfying but that's what Maven gives us.
That being said, there are many reasons why you should rather split your project into several modules, with one module containing only client-side code and producing JavaScript and associated resources (through the GWT compiler) and one with only server-side dependencies; that way you never risk putting client-side classes or dependencies into your WAR.
See http://blog.ltgt.net/announcing-gwt-maven-archetypes-project/ for more about it, and sample projects (in the form of Maven archetypes).
If I understand you correctly, you could exclude the artifact when building the WAR. Something like
<build>
...
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>2.5</version>
...
<configuration>
<packagingExcludes>
WEB-INF/lib/slf4j-gwt-*.jar
</packagingExcludes>
</configuration>
</plugin>
...
</build>
should work.
Cheers,

Maven WAR dependency - cannot resolve package?

I have a war dependency:
<dependency>
<groupId>my.package</groupId>
<artifactId>myservices</artifactId>
<version>0.3</version>
<type>war</type>
</dependency>
Now, this exists in my local repository, and the class exists at WEB-INF/classes/my/package/myservices. When I go to use myservices, however, I get package my.package does not exist. Intelli-J knows to change myservices into my.package.myservices, but trying to import seems to not work at all.
Is there something special I need to do with this war dependency?
As pointed out in the other answers:
In Maven, you cannot just load classes from a WAR artifact the way you can from a JAR artifact.
Therefore, the recommendation is to split off a separate Maven JAR project with the classes you want to reuse, and depend on this project in both the original WAR and the new project.
However, if for some reason you cannot / do not want to split the WAR project, you can also tell Maven that you need a JAR artifact in addition to the WAR. Put this into the POM of your WAR project:
<build>
...
<plugins>
...
<plugin>
<artifactId>maven-war-plugin</artifactId>
<version>2.3</version>
<configuration>
<attachClasses>true</attachClasses>
</configuration>
</plugin>
</plugins>
</build>
Then, when building the WAR project Maven will create a WAR and a JAR from it.
Source: Maven War plugin FAQ
Adapted from doc_180's comment, so it does not get overlooked.
It just doesn't work that way. war files are not supposed to be put on the classpath, but deployed to application servers (or servlet containers) that can deal with their special structure.
Of course you can probably find a custom classloader somewhere that can deal with java war files, but it's just not the way to do it.
Keep your code in a jar, include the jar in your war and in this application. But don't use a war as a dependency, unless you are building an EAR file.
WAR dependencies are handled VERY differently by Maven from JAR dependencies. They are treated as overlays.
http://maven.apache.org/plugins/maven-war-plugin/overlays.html
I think what you are looking for is something a bit different from a WAR overlay. WAR overlays merge the file structures with a "closest wins" model, but that means that things like web.xml are replaced by closest wins, not merged.
If you want merging (which is closer to what most people think of when they start talking about WAR dependencies) you should look at the Cargo uberwar plugin.
http://cargo.codehaus.org/Merging+WAR+files
If your goal is simply to share some classes between two WARs, you should probably just put those classes into a JAR project. Maven in particular is really designed to work on a pom.xml -> a single artifact model (JAR/WAR/etc). Trying to take a single pom.xml and have it emit, say, a JAR for some stuff and a WAR for other stuff is going to be very painful.
Incidentally, if you are working on a team larger than one person, you are going to want an artifact management server pretty fast (e.g. Artifactory, Nexus or Archiva) or you will go crazy dealing with this stuff. ;)
In a WAR, the classes must be located at WEB-INF/classes/... not at classes/....
Anyway I never have tried to reference other classes from a WAR (not JAR), and I do not know if this is possible.
Make sure the dependency is installed in your local repository.
The local repo should look like:
.m2/my/package/myservices/0.3/myservices-0.3.war
If this is not the case, then install the war into the local repository before using it in the dependency:
mvn install:install-file -Dfile="[path-to-war]" -DgroupId=my.package -DartifactId=myservices -Dversion=0.3 -Dpackaging=war -DcreateChecksum=true -DgeneratePom=true

Categories