Maven assembly : add different version of the same artifact - java

I create my application archive with the maven assembly plugin.
All the dependency present in my pom are included without any problem.
Now I need to include two or more version of the same artifact.
If in my pom I put
<dependencies>
[...]
<dependency>
<groupId>db.test</groupId>
<artifactId>my-model</artifactId>
<version>1.0.3</version>
</dependency>
<dependency>
<groupId>db.test</groupId>
<artifactId>my-model</artifactId>
<version>1.1.0</version>
</dependency>
</dependencies>
Of source the dependenvcy resolver remove the old version and only the 1.1.0 is packaged in the archive
I try to include the jar by using assembly xml descriptor file. And I didn't find any solution.
A possible solution will be to manually put all the needed model.jar inside a folder and tell the assembly to copy it in the archive. But I'm looking for a more configurable solution.
Any idea ?

I found a solution by using maven-dependency-plugin to copy resolved pom dependencies and additional jar.
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.1</version>
<executions>
<execution>
<id>copy-dependencies</id>
<phase>package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/lib</outputDirectory>
<overWriteReleases>false</overWriteReleases>
<overWriteSnapshots>false</overWriteSnapshots>
<overWriteIfNewer>true</overWriteIfNewer>
<includeScope>runtime</includeScope>
</configuration>
</execution>
<execution>
<id>copy-model</id>
<phase>package</phase>
<goals>
<goal>copy</goal>
</goals>
<configuration>
<artifactItems>
<artifactItem>
<groupId>my.test.pkg</groupId>
<artifactId>my-model</artifactId>
<classifier>server</classifier>
<version>1.0.3</version>
<type>jar</type>
</artifactItem>
<artifactItem>
<groupId>my.test.pkg</groupId>
<artifactId>my-model</artifactId>
<classifier>server</classifier>
<version>1.1.0</version>
<type>jar</type>
</artifactItem>
</artifactItems>
<outputDirectory>${project.build.directory}/lib</outputDirectory>
</configuration>
</execution>
</executions>
Now I just have to add the following lines in my assembly xml
<fileSet>
<directory>${project.build.directory}/lib</directory>
<outputDirectory>/lib</outputDirectory>
<filtered>false</filtered>
<includes>
<include>*.jar</include>
</includes>
<fileMode>0600</fileMode>
</fileSet>

Maven assumes it doesn't make any sense to have more than one version of a module at once. It assumes that a newer version replaces the older version. If it doesn't it is not the same module. I suggest you give the newer module a different name and make sure it has different packages to avoid choising a random module.
In general Maven tried to encourage good application design and deliberately makes it difficult to do things it has determined to be a bad idea.

Another ugly solution might be to use WAR file overlays, exploiting the fact that this mechanism pays no attention to the versions of component JAR files when applying the overlays.

I agree, different versions means replacing the older one. If we have to consume two different versions of a webservice for some business requirement. It is a good idea to generate the stubs in different packages and while adding to maven you can specify different them in groupid. This should work.

Related

Spring Boot Layered jar: Extract layers.xml to separate dependency

I'm starting to catch up on the capabilities of the repackage goal in spring-boot-maven-plugin.It looks promising, but I need to fine-tune it a little.
I can easily do that by creating a layers.xml file somewhere in my project, but the problem is that I don't only have 1 project, but rather half a dozen. All of the projects need the same kind of layering, but I don't really want to copy the same configuration for every project I want to use it on.
A nice-looking solution would be to extract that configuration file into a separate jar for example and have the plugin take the config file from there, but I see no way of doing it. Is there any other solution that doesn't involve me copying the configuration file to every project I have?
Unfortunately, even though the projects I have use the same parent, but are not in the same multi-module project.
I managed to work out a solution.
Before asking the question my spring-boot-mave-plugin config looked something like this:
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<layers>
<enabled>true</enabled>
</layers>
</configuration>
<executions>
<execution>
<id>repackage</id>
<goals>
<goal>repackage</goal>
</goals>
<phase>package</phase>
<configuration>
<layers>
<enabled>true</enabled>
<configuration><!-- something like classpath:layers.xml --></configuration>
</layers>
<classifier>exec</classifier>
</configuration>
</execution>
</executions>
<dependencies>
<dependency>
<groupId>artifact</groupId>
<artifactId>with-layers.xml</artifactId>
<version>...</version>
</dependency>
</dependencies>
</plugin>
The solution becomes one step more convoluted, by bringing in the maven-dependency-plugin, which downloads the before mentioned dependency and unpacks it in the build folder with this configuration:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>3.1.1</version>
<executions>
<execution>
<id>copy-shc-build-tools</id>
<goals>
<goal>unpack</goal>
</goals>
<phase>package</phase>
<configuration>
<artifactItems>
<artifactItem>
<groupId>artifact</groupId>
<artifactId>with-layers.xml</artifactId>
<version>...</version>
<type>jar</type>
<outputDirectory>${project.build.directory}</outputDirectory>
<includes>**/layers.xml</includes>
</artifactItem>
</artifactItems>
</configuration>
</execution>
</executions>
<configuration>
<overWriteReleases>false</overWriteReleases>
<overWriteSnapshots>true</overWriteSnapshots>
</configuration>
</plugin>
In turn, the line <configuration><!-- something like classpath:layers.xml --></configuration> becomes <configuration>${project.build.directory}/layers/layers.xml</configuration>.
The documentation for Spring Boot Maven Plugin states you can set the path to the layers.xml manually, so why not have all pom.xml point to the same location?
<project>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<version>2.3.2.RELEASE</version>
<configuration>
<layers>
<enabled>true</enabled>
<configuration>${project.basedir}/../layers.xml</configuration>
</layers>
</configuration>
</plugin>
</plugins>
</build>
</project>
The /../ means one level higher from the project directory. So say you have a bunch of projects in one directory, put the layers.xml there and it'll work.
Another approach could be to reuse the Maven Plugin declaration by moving it to a so-called parent POM. This is a technique where the common/shared parts of the POM files of a series of projects is moved to a single POM file (the parent POM). Here's an example

Java and Scala not working together

I have 2 projects, one maven java and another maven Scala.
The scala one is a library, that I want to use in my java application.
I have the following dependencies in both :
<dependency>
<groupId>org.scala-lang</groupId>
<artifactId>scala-compiler</artifactId>
<version>2.9.0-1</version>
<scope>compile</scope>
</dependency>
<dependency>
<groupId>org.scala-lang</groupId>
<artifactId>scala-library</artifactId>
<version>2.9.0-1</version>
</dependency>
and as found on googling, this maven-scala-plugin in both apps
<plugin>
<groupId>org.scala-tools</groupId>
<artifactId>maven-scala-plugin</artifactId>
<version>2.14.3</version>
<configuration>
<charset>UTF-8</charset>
<jvmArgs>
<jvmArg>-Xmx1024m</jvmArg>
</jvmArgs>
</configuration>
<executions>
<execution>
<id>compile</id>
<goals>
<goal>compile</goal>
</goals>
<phase>compile</phase>
</execution>
<execution>
<id>test-compile</id>
<goals>
<goal>testCompile</goal>
</goals>
<phase>test-compile</phase>
</execution>
<execution>
<phase>process-resources</phase>
<goals>
<goal>compile</goal>
</goals>
</execution>
</executions>
</plugin>
The source & target specified in maven for both are java 1.6 and I'm using Netbeans (tried even from command-line but no use)
I build the scala project and then mark a system dependency to it in the maven java project.
Infact, I'm using the goose parser (scala project - https://github.com/jiminoc/goose)
But whenever I run the java project/file, I get ClassNotFoundException for the parser classes.
Tried everything out there for hours now but no success.
Please help.
Also, to mention I've tried building with scala version 2.10.4 but it also has the same issue.
I build the scala project and then mark a system dependency to it in the maven java project.
System dependencies:
Dependencies with the scope system are always available and are not looked up in repository. They are usually used to tell Maven about dependencies which are provided by the JDK or the VM.
Since your Scala project isn't provided by the JDK or the VM, it isn't a system dependency. You would run into exactly the same problem if you had two Java projects. Just remove <scope>system</scope>.

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.

Disable deploy of jnilib

My users have been calling out for easily distributed native binaries with my library. I've got this working by distributing the natives in jars, which are extracted at runtime into a temporary directory.
However, the maven-native-plugin requires that the native is packaged as a jnilib (OS X), so (Linux) or dll (Windows). I have my own deploy target that packages a jar file and distributes that under the classifier natives. It's a bit annoying that this needs a special classifier.
How can I disable the deploy of the jnilib/so/dll?
How can I distribute my jar without any special classifier?
I do a similar thing, but I pack the native libraries inside zip files. After that, in the artifact that needs them, I pull and unpack the zip file with the maven dependency plugin:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<id>unzip</id>
<phase>prepare-package</phase>
<goals>
<goal>unpack</goal>
</goals>
<configuration>
<artifactItems>
<artifactItem>
<groupId>foo</groupId>
<artifactId>bar</artifactId>
<version>1.0.0</version>
<type>zip</type>
<overWrite>true</overWrite>
<includes>**/*.dll</includes>
<outputDirectory>${project.build.directory}/natives</outputDirectory>
</artifactItem>
</artifactItems>
</configuration>
</execution>
</executions>
</plugin>
As you can see I don't use any classifiers.

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

Categories