maven assembly plugin: add a file into a dependency jar - java

There is this maven module, say prj-package-module, to package the project artifacts into a tar file using maven-assembly-plugin. There are also jars added as dependencies in the prj-package-module/pom.xml and packaged into the tar file.
Now the requirement is to add a file, prj-pakacge-module/src/main/resources/file.xml to one of these dependency jars before packaging into the tar file. How can I achieve this?
Edit: The file is a JNLP with list of dependency jars dynamically added to it. For security reasons, Javaws also requires the JNLP file to be added a jar and the jar to be signed. This is where I hit the problem.

Here is a maven solution to dynamically unpack an existing dependency, add (copy) a resource to the unpacked folder, repack (jar) the hole and as such get a modified copy of the initial jar.
A sample pom file doing exactly that for the junit dependency:
<build>
<plugins>
<!-- unpack step -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.10</version>
<executions>
<execution>
<id>unpack</id>
<phase>prepare-package</phase>
<goals>
<goal>unpack</goal>
</goals>
<configuration>
<artifactItems>
<artifactItem>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<type>jar</type>
<outputDirectory>${project.build.directory}/unpack-tmp</outputDirectory>
<includes>**/*.class,**/*.xml</includes>
</artifactItem>
</artifactItems>
</configuration>
</execution>
</executions>
</plugin>
<!-- add the additional resource step -->
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<version>2.7</version>
<executions>
<execution>
<id>copy-resources</id>
<phase>prepare-package</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>${basedir}/target/unpack-tmp</outputDirectory>
<resources>
<resource>
<directory>src/main/resources</directory>
<include>test.properties</include>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
<!-- repack step -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.6</version>
<executions>
<execution>
<id>repack</id>
<phase>prepare-package</phase>
<goals>
<goal>jar</goal>
</goals>
<configuration>
<classesDirectory>${basedir}/target/unpack-tmp</classesDirectory>
<finalName>junit-modified</finalName>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
What it is actually doing:
As part of the prepare-package phase we are adding three steps to create a modified jar from a dependency
First step: unpack the dependency via the Maven Dependency Plugin and its unpack goal: an unpacked folder will be created to the tmp folder unpack-tmp
Second step: copy the concerned resource via the Maven Resources Plugin and its copy-resources goal.
Third step: re-pack the whole via the Maven Jar Plugin and its classic jar goal
Running the sample above, the junit-modified.jar file will appear in the target folder of the maven project.
The order of the plugin configurations above is important to respect the steps flow as part of the same phase.
Then, you have one additional file to add to your fat-jar, which is indeed the modified jar you were probably looking for.
If you don't need a dynamic approach, a better approach would be to do it once and have a classified version of that dependency as explained in this other SO post.
Alternatively, move it to a Maven profile so that at least it is not part of the default build.

It seems that you're trying to modify a dependency of the maven project before packaging it into the final artifact of the project.
This is dodgy. If that jar/library (the dependency) is yours, then modify the pom of that jar, rebuild it, and then have the current project resolve the latest artifact.
If, otherwise, the dependency jar is not yours, then it should suffice to have the resource (prj-pakacge-module/src/main/resources/file.xml) in the current project (the one you're building now), as the end result will be the same (as long as the assembly plugin is set to flatten all artifact jars in the target uber/fat jar...

Related

Maven copy-dependencies + shade - classpath management

To package a maven project with its dependencies, among many solutions, one may use maven-dependency-plugin with its goal copy-dependencies to get the dependencies in a folder besides, or one may use maven-shade-plugin to get all the code in a single jar.
I actually do both: I choose to have external dependencies (e.g. apache commons) as external libs, and my own dependencies (I have a multi-module maven parent project) shaded into a unique jar.
And it works, except for the classpath. I copy-dependencies with option excludeGroupIds to exclude my own maven group id. I shade with option to include only my own maven group id. Before that, I jar with option to add classpath to the manifest. All set, it works. But my classpath also contains my own dependencies that were actually shaded in the final jar.
It is no big deal, because the result works even with this erroneous classpath. But I wonder if there is a simple means to have the correct classpath, in order not to expose my internal structure to my users.
Here is a basic example demonstrating the problem:
<groupId>com.foo.bar</groupId>
<artifactId>com.foo.bar.launcher</artifactId>
<dependencies>
<dependency>
<groupId>com.foo.bar</groupId>
<artifactId>com.foo.bar.utils</artifactId>
<version>0.0.1</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.8.1</version>
</dependency>
</dependencies>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<classpathPrefix>lib/</classpathPrefix>
</manifest>
</archive>
</configuration>
</plugin>
<plugin>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>copy-dependencies</id>
<phase>package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/lib</outputDirectory>
<excludeGroupIds>com.foo.bar</excludeGroupIds>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>shade</goal>
</goals>
<configuration>
<artifactSet>
<includes>
<include>com.foo.bar:*</include>
</includes>
</artifactSet>
</configuration>
</execution>
</executions>
</plugin>
The resulting manifest contains this:
Class-Path: lib/com.foo.bar.utils-0.0.1.jar lib/commons-lang3-3.8.1.jar while the com.foo.bar.utils one does not exist.
If you look into the following mvnrepository link maven shade plugin depends upon maven dependency tree. As per the above pom.xml maven dependency plugin, you have excluded com.foo.bar dependency. You can omit the maven-dependency-plugin to create fat jar. It is not mandatory to use in case of shade plugin.
You can use the following command to check and copy all the dependencies used in the project.
mvn dependency:copy-dependencies
https://mvnrepository.com/artifact/org.apache.maven.plugins/maven-shade-plugin/3.2.1

maven multi module dependency version

I have a multi-module maven project: Module A depends on Module B. When Module B is built it is named ModuleB.jar and copied to target directory. Now in Module A's pom I have to put
<dependency>
<groupid>com.mycompany.app</groupid>
<artificatId>ModuleB</artifactId>
<version>1.0</version>
</dependency>
I have to put the version number, but then now I have two same Module B jars: ModuleB.jar (no version in name) and ModuleB-1.0.jar along with ModuleA.jar in the target directory.
I prefer to keep the version number out from the jar's final names since we have other legacy apps depending on these jars
Is there anyway to add Module B as a dependency in Module A's pom without the version number? Any clean solutions at all or am I just making life difficult for myself?
EDIT:
To clarify: These modules are built from a parent pom as jars and are copied, along with their dependencies, to a target directory outside of the project's parent directory. Hence the reason why there are two ModuleB jars: one when Module B is compiled and packaged with the finalname set as ModuleB.jar and one when Module A is compiled and packaged along with its dependencies, which includes Module B but with the name ModuleB-1.0.jar
Thanks!
The copy-dependency execution (I could strip out the version during the copy but then I would lose versions on 3rd party jars such as Spring jars =/ ):
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.8</version>
<executions>
<execution>
<id>copy-dependencies</id>
<phase>package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<outputDirectory>${build.dir}/lib</outputDirectory>
<overWriteIfNewer>true</overWriteIfNewer>
<stripVersion>false</stripVersion>
</configuration>
</execution>
</executions>
</plugin>
So the problem was that I was copying my internal modules twice: once when running maven-jar-plugin (with no version in finalname) and once when running maven-dependency-plugin, and both plugins are outputting to the same target directory giving me ModuleB.jar and ModuleB-1.0.jar.
So in the parent pom I configured the plugins:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.4</version>
<configuration>
<outputDirectory>${build.dir}/lib</outputDirectory>
</configuration>
</plugin>
and
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.8</version>
<executions>
<execution>
<id>copy-dependencies</id>
<phase>package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<outputDirectory>${build.dir}/lib</outputDirectory>
<overWriteIfNewer>true</overWriteIfNewer>
<stripVersion>false</stripVersion>
<excludeGroupIds>com.mycompany.app</excludeGroupIds>
</configuration>
</execution>
</executions>
</plugin>
The first plugin is building all my child modules and jar'ing them to the output directory specified. the second plugin is copying all my module's dependencies to the same output directory in the first plugin sans the internal modules using <excludeGroupIds>
Thank you for helping me realize there was a simple solution!

Maven checkstyle https configuration

I have the following maven check style plugin configuration
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-checkstyle-plugin</artifactId>
<configuration>
<consoleOutput>true</consoleOutput>
<configLocation>https://someUtl.com/file.xml</configLocation>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>check</goal>
</goals>
</execution>
</executions>
</plugin>
Pay attention on
<configLocation>https://someUtl.com/file.xml</configLocation>
file.xml can be downloaded by browser, but it require a login and password. Is there a way to specify these login/password in maven or in plugin configuration?
Underneath, this uses Plexus which in turn pretty much does URL.openStream().
This answer shows how an Authenticator can be used for that in Java code, but I was unable to find a Maven equivalent for that. I'm inclined to say that it's not possible.
Alternatively, you might be able to download the file in a separate mojo execution, then point the configLocation to the downloaded file, which could be anywhere down your target folder.
I think that this answer gives a few nice ideas about how to download files in Maven. Their first is that if your file is a Maven artifact, you could use the Maven Dependency Plugin.
And then we come full circle, because if your Checkstyle configuration were to be contained in a Maven artifact, you would not have to set configLocation to a remote location, but you'd add that artifact as a dependency of your Checkstyle plugin execution. Since Maven defines everything in terms of dependencies, that is my way to go, and that is exactly how I set up my own Checkstyle configurations.
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-checkstyle-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>check</goal>
</goals>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>com.totaalsoftware.incidentmanager</groupId>
<artifactId>checkstyle-config</artifactId>
<version>2.0.0-SNAPSHOT</version>
</dependency>
</dependencies>
<configuration>
<configLocation>checkstyle.config.xml</configLocation>
...
</configuration>
</plugin>
Clearly, in the above example, checkstyle.config.xml resides in the root of the checkstyle-config JAR.

Renaming Maven dependency in WAR's WEB-INF/lib folder

I need to have a JAR dependency in the Maven generated WAR's WEB-INF/lib folder as x-1.0.final.jar instead of x-1.0.jar, which is the name it has in the repository. What would be the best way to achieve this?
In my POM I have:
<dependency>
<groupId>foo</groupId>
<artifactId>x</artifactId>
<version>1.0</version>
</dependency>
I want this to appear in the WEB-INF/lib folder as x-1.0.final.jar.
It's and external dependency on Maven Central I don't have control over. Also I don't want to force everyone using this to redeploy the dependency to their local repositories.
Is there a Maven plugin that I could utilize or should I start coding my own?
You can use maven-dependency-plugin to include artifact under the name that you need.
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<goals>
<goal>copy</goal>
</goals>
<configuration>
<artifactItems>
<artifactItem>
<groupId>foo</groupId>
<artifactId>x</artifactId>
<version>1.0</version>
<type>jar</type>
<outputDirectory>${project.build.directory}/${project.build.finalName}/WEB-INF/lib</outputDirectory>
<destFileName>x-1.0.final.jar</destFileName>
</artifactItem>
</artifactItems>
</configuration>
</execution>
</executions>
</plugin>
By default, maven-dependency-plugin is bound to the process-sources phase that seems just enough for your task. Remember to set the scope provided for the artifact in dependencies so that it is not automatically included by the war plugin.
You may want to see if the outputFileNameMapping parameter of maven war plugin can help you.
I know that I'm replying to an old thread, but I needed to perform the above and found this thread helpful. The way I found to achieve this was to perform a 2 step process:
Use the maven-war-plugin to exclude the original jar file from the deliverable.
Use the maven-dependency-plugin to copy the original jar file to the new-named jar file and place this in the WEB-INF/lib directory.
So, by way of illustration, this is how to specify the file you wish to exclude. In this case x-1.0.jar :
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.6</version>
<configuration>
<!-- Exclude file: x-1.0.jar from packaging -->
<packagingExcludes>WEB-INF/lib/x-1.0.jar</packagingExcludes>
</configuration>
</plugin>
Also specify that a copy must be performed of the file to the new name (x-1.0.final.jar) but this needs to run BEFORE packaging occurs. This is specified by the phase: 'prepare-package':
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<phase>prepare-package</phase>
<goals>
<goal>copy</goal>
</goals>
<configuration>
<artifactItems>
<artifactItem>
<groupId>the group of the x jar</groupId>
<artifactId>x</artifactId>
<type>jar</type>
<outputDirectory>${project.build.directory}/${project.build.finalName}/WEB-INF/lib</outputDirectory>
<destFileName>x-1.0.final.jar</destFileName>
</artifactItem>
</artifactItems>
</configuration>
</execution>
</executions>
</plugin>
In my example I wasn't hard-coding 1.0 but I think this should work for the original posters question.
Sorry I dont understand your question fully what is the code you have for importing this jar in the POM?
If the Jar you wish to import is called that in the repository and you are importing the correct file in your POM then you shouldn't have to worry about naming conventions of the JAR file.
What i believe you may have to do is rename the file in the repository you can do this simply by going into the Repository Users/.m2 in a explorer window and tracking down the file and renaming it, note this may have implications on other projects.
What i suggest you do is copy the file rename it and add it to the repository with the new artifact id x-1.0.final.jar
mvn install:install-file -Dfile=<path-to-file> -DgroupId=<group-id> \
-DartifactId=<artifact-id> -Dversion=<version> -Dpackaging=<packaging>
fill in the <>
Hope this helps
Chris

best practice: how to host server-side code in the maven repository

What is the best way to put javascript/html/css code in the maven repository, so that is easily usable by java projects.
Is there a way to do it such that the included project can be easily made "web-visible" by the including project?
For example assume I write a very useful tricks.js file an put it in the mvn repository.
Is it possible to create a web project that adds tricks.js as a dependency and then doing
<script src="/some/thing/tricks.js"/>
causes the tricks.js file to be served?
External resources should be packaged into an artifact and published to the repository (for simplicity use a jar artifact, but you could specify an assembly to package a zip instead to make it clear what the artifact is for). The maven-dependency-plugin unpacks the jar's contents into a specified location in the war project. That folder is then specified as an external web resources directory for the maven-war-plugin.
The following configuration will unpack the contents of my-resources into the target/external-resources directory, then include the contents of that folder in the war as if they'd been defined in src/main/resources.
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>unpack</id>
<phase>generate-resources</phase>
<goals>
<goal>unpack</goal>
</goals>
<configuration>
<artifactItems>
<artifactItem>
<groupId>name.seller.rich</groupId>
<artifactId>my-resources</artifactId>
<version>1.0.0</version>
<type>jar</type>
<overWrite>false</overWrite>
</artifactItem>
</artifactItems>
<outputDirectory>${project.build.directory}/external-resources</outputDirectory>
<overWriteReleases>false</overWriteReleases>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-war-plugin</artifactId>
<version>2.0</version>
<configuration>
<webResources>
<resource>
<directory>${project.build.directory}/external-resources</directory>
</resource>
</webResources>
</configuration>
</plugin>
You can pack it into jar and then unpack it by maven plugins.

Categories