Exclude Java package from dependency jar - maven

I want to use jar from third party vendor. But in this jar I have old version of Java package org.osgi.framework I need to find some way to exclude the package from the main project. Something like this:
<dependency>
<groupId>com.ibm</groupId>
<artifactId>com.ibm.ws.admin.client</artifactId>
<version>8.5.0</version>
<exclusions>
<exclusion>org.osgi.framework</exclusion>
</exclusions>
<type>jar</type>
</dependency>
Can you recommend some solution?

Although a better solution would be to re-pack the dependency (without the unwanted package) with a classifier (as described in this answer) and publish it on your enterprise Maven repository (or install it into your local Maven cache, if it's a personal project), below is a different solution which should also suit your needs.
You could have a multi-module Maven project, having a module with just this dependency and in it you could use the Maven Shade Plugin and its filters property as explained in its official example.
As per documentation, the filters element:
Archive Filters to be used. Allows you to specify an artifact in the form of a composite identifier as used by artifactSet and a set of include/exclude file patterns for filtering which contents of the archive are added to the shaded jar
In your case, the following configuration should apply the filter:
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.4.3</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<filters>
<filter>
<artifact>com.ibm:com.ibm.ws.admin.client</artifact>
<excludes>
<exclude>org/osgi/framework/**</exclude>
</excludes>
</filter>
</filters>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
The generated jar from the package phase should not contain that package any longer. As part of the Maven output you should see:
[INFO] --- maven-shade-plugin:2.4.3:shade (default) # test-checksum ---
[INFO] Including com.ibm:com.ibm.ws.admin.client:jar:8.5.0 in the shaded jar.
[INFO] Replacing original artifact with shaded artifact.
You can verify the content of the generated jar, the filtered package should not be there.
Then, the output of this module will have the "new"/filtered jar you were looking for. Then the consumer module would just need to have a dependency on this module and as such have the filter applied.
An example of such a multimodule project would be:
+ aggregator/parent project
- filtered-dependency-module (applying the shade filter)
- consumer-module (having dependency on the filtered module)
Update
Further note: in the module which applies the filter, you should declare the dependency as optional so that the consumer module doesn't bring it in transitively again.
<dependencies>
<dependency>
<groupId>com.ibm</groupId>
<artifactId>com.ibm.ws.admin.client</artifactId>
<version>8.5.0</version>
<optional>true</optional>
</dependency>
</dependencies>
Optional doesn't affect the module itself, only the consumer one. And the Shade plugin will keep on working (I re-tested it, just in case).

Related

Does the Maven Versions Plugin read rules also from classpath?

The Maven Versions Plugin supports the defintion of rules to customize the version resolution process for goals as versions:display-plugin-updates or versions:display-dependency-updates. The location of the rules file can be specified by the rulesUri and the functionality behind this is provided by Maven Wagon.
Therefore I would like to know if it is also supported to provide a rule set within a Jar? I would like to one rule set for multiple projects.
A patch by me has been released with version 2.5 of the Versions Maven Plugin
Now it is possible to create a version rules file and to place it on the classpath.
This example below shows how to reference a rules file called rules.xml
which is provided in a jar on the classpath:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>versions-maven-plugin</artifactId>
<version>2.7</version>
<executions>
<execution>
<id>default-cli</id>
<configuration>
<rulesUri>classpath:///rules.xml</rulesUri>
</configuration>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>your.organisation</groupId>
<artifactId>rulesspec</artifactId>
<version>1234</version>
</dependency>
</dependencies>
</plugin>
Please keep in mind that the provided URI must start with classpath://.

Maven shaded jar used as external project dependency

I have used maven shade plugin in my project to relocate all dependency jar classes under one package e.g., org.shade.*
When I try to use that shaded jar in other application as maven dependency it pulls dependency jar's.
My expectation is when uber/shaded jar included as maven dependency it should not pull any other dependent class jar, Since already those classes are repackaged within shaded jar.
The classic scenario is:
A project producing an uber-jar has its own dependencies (dependency elements in its pom.xml file) which then are packaged together in one uber-jar as Maven artifact
When using this uber-jar as a dependency (dependency element) of another project, Maven would then inspect its <artifact>-<version>.pom file (published together with the final artifact into the Maven repository), which is basically a renamed copy of its original pom.xml file, where dependencies (dependency element) were declared (exactly the dependencies packaged into the uber-jar).
Since you already have them packed, you would then like to ignore the .pom file (and its dependencies element), for that you need to add exclusions as following:
<dependency>
<groupId>com.sample</groupId>
<artifactId>something-uber</artifactId>
<version>some-version</version>
<exclusions>
<exclusion>
<groupId>*</groupId>
<artifactId>*</artifactId>
</exclusion>
</exclusions>
</dependency>
Note: the feature above is only available since Maven 3.2.1.
As such, you are making clear to Maven you don't want any transitive dependency and Maven dependency mediation would then not trigger them.
As a side note: this is not a good practice to have an uber-jar as dependency of a project: it will just make maintenance harder since you can't control transitive dependencies via dependencyManagement or dependencies order of the dependent project. As such you will always need to re-pack the uber jar whenever a dependency (one of its transitive one) would need maintenance (change version and so on) and have much less control on the dependent project (again, harder maintenance).
As the pom.xml on your source project that produces the uber jar declares transitive dependencies, if you include it as dependency into an external project then Maven will try to get these ( even if these are already included on the uber jar ).
I share a solution that let you avoid to explicitly exclude all transitive dependencies including it into an external project as explained by #A_DiMatteo on his solution ( I agree also with him about to avoid to use uber jar as dependency if not strictly necessary to do it for some reason ). As result then you should be able to include your uber jar dependency without using exclusions element as follow:
<dependency>
<groupId>com.sample</groupId>
<artifactId>something-uber</artifactId>
<version>some-version</version>
</dependency>
Premise: my goal was to provide both uber ( without transitive dependency declared on pom ) and thin jars on my repository. So my solution "A" is based on this scenario and currently has the limit that the shaded jar is uploaded 2 times on repository.
To provide only the uber jar see "B" solution below
For a possible solution for "A" limit see the UPDATE section at the end
A) Provide both thin and uber jars on repository
1- On your source project configure on your something module pom.xml the following maven-shade-plugin as follow:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.2</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<finalName>something-uber-${project.version}</finalName>
</configuration>
</execution>
</executions>
</plugin>
Then use the build-helper-maven-plugin plugin to attach the new artifact with "uber" classifier on module:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<version>1.2</version>
<executions>
<execution>
<id>attach-artifacts</id>
<phase>package</phase>
<goals>
<goal>attach-artifact</goal>
</goals>
<configuration>
<artifacts>
<artifact>
<file>
${project.build.directory}/something-uber-${project.version}.jar
</file>
<classifier>uber</classifier>
</artifact>
</artifacts>
</configuration>
</execution>
</executions>
</plugin>
This will generate as results of the maven install phase the following two jars on target/ directory:
40K something-0.1.0.jar
7M something-uber-0.1.0.jar
WARN: Executing then the maven deploy phase both jars will be uploaded on repository! The target here should be to upload only the thin jar skipping deploy for shaded jar in order to leave it as a local artifact ( See the UPDATE section at the end for a possible fix )
2- Create then another module on your source project named something-uber adding following dependencies and plugin:
<dependencies>
<dependency>
<groupId>com.sample</groupId>
<artifactId>something</artifactId>
<version>${project.version}</version>
<classifier>uber</classifier>
<exclusions>
<exclusion>
<artifactId>*</artifactId>
<groupId>*</groupId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>2.2</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
Note the followings on including the dependency:
the classifier should be equals to uber ( the one you've specified attaching new artifact using build-helper-maven-plugin on first module )
the exclusions are specified.
Executing at the end the maven deploy phase on this module the shaded jar will be uploaded on repository and you we'll be able to add it as dependency into an external project as follow:
<dependency>
<groupId>com.sample</groupId>
<artifactId>something-uber</artifactId>
<version>0.1.0</version>
</dependency>
B) Provide only uber jar on repository
Starting from solution "A" if you want to avoid to provide the thin jar on repository you should avoid on point 1 to specify finalName on maven-shade-plugin configuration and so avoid also the build-helper-maven-plugin plugin as there isn't a new artifact to attach.
Doing this, deploying the module you'll have only the uber jar on target/ as default one ( without classifier ):
7M something-0.1.0.jar
You should also skip the upload otherwise you'll have also here two fat jars uploaded ( something-0.1.0.jar & something-uber-0.1.0.jar ).
To do this add the following plugin on the same module:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-deploy-plugin</artifactId>
<version>2.8.2</version>
<configuration>
<skip>true</skip>
</configuration>
</plugin>
At the end on point 2 just avoid to specify the classifier on adding the dependency as follow:
<dependencies>
<dependency>
<groupId>com.sample</groupId>
<artifactId>something</artifactId>
<version>${project.version}</version>
<exclusions>
<exclusion>
<artifactId>*</artifactId>
<groupId>*</groupId>
</exclusion>
</exclusions>
</dependency>
</dependencies>
UPDATE: Skip first shaded jar upload on A) solution
After searching for a solution for a while without success I decided to fork the maven-deploy-plugin plugin from GitHub and work for a new feature in order to skip shaded jar created on first module adding the plugin configured as follow:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-deploy-plugin</artifactId>
<version>3.0.0-SNAPSHOT</version>
<configuration>
<skipAttachedArtifacts>
<artifact>
<groupId>com.sample</groupId>
<artifactId>something</artifactId>
<version>${project.version}</version>
<packaging>jar</packaging>
<classifier>uber</classifier>
</artifact>
</skipAttachedArtifacts>
</configuration>
</plugin>
Currently using the maven-deploy-plugin plugin all artifacts are excluded from deploy while target here is to exclude only a specific one. On my fork I've introduced the "skipAttachedArtifacts" configuration parameter in order to specify attached artifacts to exclude from deploy.
Here is the link on my forked project on GitHub:
https://github.com/gregorycallea/maven-deploy-plugin
Here the link instead to the pull request I've submitted on apache plugin project:
https://github.com/apache/maven-deploy-plugin/pull/3

Can I have maven artifact run maven plugin when it is installed?

I have created a Maven plugin (called unpackTemplates) that unpacks a dependency jar file and copies resource files (in this case, templates) from it into a specific location in a project.
Right now, I put the following into the pom file of every project that has a dependency with templates. It looks like:
<project>
<groupId>DuriansAreDope</groupId>
<artifactId>DuriansAreDope</artifactId>
<version>0.0.1-SNAPSHOT</version>
<build>
<plugin>
<groupId>mycorp</groupId>
<artifactId>unpackTemplates</artifactId>
<version>1.0</version>
<executions>
<execution>
<configuration>
<groupId>com.mycorp.lib</groupId>
<version>1.0</version>
<artifactId>Lib-With-Templates</artifactId>
</configuration>
<goals>
<goal>unpackTemplates</goal>
</goals>
<phase>generate-sources</phase>
</execution>
</executions>
</plugin>
<pluginManagement>....</pluginManagement>
</build>
<dependencies>
<dependency>
<groupId>com.mycorp.lib</groupId>
<artifactId>Lib-With-Templates</artifactId>
<version>1.0</version>
</dependency>
</dependencies>
</project>
The above project pom works for us. It calls the plugin and the plugin does it's job. However, we'd like to avoid adding the plugin section to the pom of every project.
It would make more sense to put that plugin section in the dependencies pom. This way the project pom does not need to be modified beyond adding the <dependency> tags as usual. And the dependency has it's plugin run wherever it is installed.
I've seen that the pom file for Gson contains a <build><plugins>...</plugins></build> section in it. When I give my dependencies the following pom files, however, the plugin is not run (although the dependency is found, downloaded, installed, etc correctly).
<project>
<groupId>com.mycorp.lib</groupId>
<artifactId>Lib-With-Templates</artifactId>
<version>1.0</version>
<build>
<plugin>
<groupId>mycorp</groupId>
<artifactId>unpackTemplates</artifactId>
<version>1.0</version>
<executions>
<execution>
<configuration>
<groupId>com.mycorp.lib</groupId>
<version>1.0</version>
<artifactId>Lib-With-Templates</artifactId>
</configuration>
<goals>
<goal>unpackTemplates</goal>
</goals>
<phase>generate-sources</phase>
</execution>
</executions>
</plugin>
<pluginManagement>....</pluginManagement>
</build>
</project>
Any ideas what I'm doing wrong, or if the Gson pom is simply doing something else entirely?
(NB: The groupId/version/artifactIds in <configuration> are necessary because they are (string) parameters to the plugin; presumably if I got the run-straight-from-dependency approach working I could refactor them away, but again, it's not even running the kludgy version with parameters.)
two points:
First I agree with khmarbaise in that you don't need a plugin of your own for those tasks. To unpack to a specific location you can use dependency:unpack-dependencies and outputDirectory parameter.
If you need more configuration you can use the assembly plugin to structure your artifact (which you want to unpack).
For the second point it seems to me that you want to use the contents of your lib-with-templates in many projects. Why don't you add the plugin and dependency to a parent pom which you include in every pom where you need it? Then you don't need to declare it in "every pom". If you don't really need it in every pom you can put it in a profile and choose a proper activation for it.
HTH!

How to include resources from war to another maven project

I have a maven project , which needs to copy webapp/WEB-INF/ resources from another maven project which is packaged as a war .
How do I do it ?
PLease suggest
As Bittrance said, you should use the maven dependency plugin.
The better way is to create project that include all your shared resources, probably a type zip, which is build up with the assembly plugin. This is the good "maven way". It's a better solution than unpacking a war.
Then, refer it
<dependency>
<groupId>com.mygroup/groupId>
<artifactId>my-dependencies</artifactId>
<version>1.0.0</version>
<type>zip</type>
</dependency>
Next, you use the maven dependency plugin to unpack your resources, in the directory of your choice (probably WEB-INF/ ?)
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>unpack-cfg-test-resources</id>
<goals>
<goal>unpack-dependencies</goal>
</goals>
<phase>resources</phase>
<configuration>
<outputDirectory>${project.build.directory}/WEB-INF/</outputDirectory>
<includeArtifacIds>my-resources</includeArtifacIds>
<excludeTypes>pom</excludeTypes>
<excludeTransitive>true</excludeTransitive>
</configuration>
</execution>
</executions>
</plugin>
I'm not realy sure of this code snippet (written for another purpose), but this is an example.
For more information, please follow this link : http://maven.apache.org/plugins/maven-dependency-plugin/
If you can't shared a common-project including your files, you can unpack war including only ftl (or whatever you want), but it's not a realy clean solution ;)
There is a lot of posts that deal with this subject :
Unzip dependency in maven
...
Just try with the keywords maven-dependency-plugin, unpack :)
Hope that will help you.
I can see some alternatives:
Use external references in your version control system to point all repos to the same files.
The Maven Dependency module can copy and unpack project dependencies. From there, you can use the Maven Assembly plugin (or Ant targets) to include parts of that dependency in your own installation.
At least for the FTL files, perhaps you could package them in a separate Jar file and then load them as resources through the class loader.
If the resources are filtered, you may get into problem with solution 1 if you want the filtered version and 2, 3 if you want the source version.
Hope this helps.
(This assumes your dependent project is java (jar) and not another web app, if it is a webapp I think the solution is similar).
I suggest a (slightly) different approach:
Instead of reading resources from war, add this to your war pom, to generate a jar in the artifact as well as a war:
<!-- maven war plugin config -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<configuration>
...
<attachClasses>true</attachClasses>
<classesClassifier>some-string</classesClassifier>
</configuration>
<artifactId>maven-war-plugin</artifactId>
<version>3.0.0</version>
</plugin>
...
<resources>
<!-- This is for inclusion in the jar, so dependent module can load it -->
<resource>
<targetPath>some-path</targetPath>
<directory>src/main/webapp/path...</directory>
<includes>
<include>your-resource</include>
</includes>
</resource>
</resources>
And this to your consuming pom, so the generated jar will be loaded:
<dependency>
<groupId>com.company</groupId>
<artifactId>...</artifactId>
<classifier>some-string</classifier>
</dependency>
Then you will be able to load the resources the usual way (getResourceAsStream("some-path/your-resource"))

Maven WAR dependency

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.
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>
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.)
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.
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.
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.

Resources