I have a project with two seperate modules that uses sqlline and another library(say OtherLib) that depends on jline. However on different versions.
External Libraries
Module1 uses Sqlline depends on jline 2.10
Module2 uses OtherLib depends on jline 0.9.94
And the two versions are incompatible.
Therefore I have set the classpaths such that Module1 will search in $HOME/lib/module1 folder first and Module2 in $HOME/lib folder first.
Is there a way to specify maven to download the artifact to a source directory first(say ../resources/lib) and then copy it to package during packaging time in assembly.xml?
I know that for copying from source directory the following code can be used.
<fileSets>
<fileSet>
<directory>../resources/lib</directory>
<outputDirectory>${HOME}/lib/module1</outputDirectory>
<directoryMode>755</directoryMode>
<fileMode>644</fileMode>
<includes>
<include>*.jar</include>
</includes>
</fileSet>
</fileSets>
Also to get maven to download the dependency I can use (for Module2)
<dependencySets>
<dependencySet>
<useProjectArtifact>false</useProjectArtifact>
<outputDirectory>${HOME}/lib</outputDirectory>
<directoryMode>755</directoryMode>
<fileMode>644</fileMode>
<includes>
<include>jline:jline:jar:0.9.94</include>
</includes>
</dependencySet>
<dependencySets>
How can I make sure jline:jline:jar:2.10 is downloaded to ../resources/lib folder first?
If you're absolutely sure, what you're doing, you can repackage one of the version using something like maven-shade-plugin. But please be absolutely sure, what you're doing.
With maven-shade-plugin you could create a new Maven module, say jline:jline_2_10:jar:1.0 and use jline:jline:jar:2.10 as a dependency. The maven-shade-plugin would then package it in your jline_2_10-1.0.jar.
Since your new artifact has its own groupId:artifactId combination, there will be no conflicts with the other jline:jline:jar:0.9.94 artifact, so you'll happily have both in the classpath.
I found a an answer here using maven-dependency-plugin
In pom.xml
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.1</version>
<executions>
<execution>
<id>copy-model</id>
<phase>package</phase>
<goals>
<goal>copy</goal>
</goals>
<configuration>
<artifactItems>
<artifactItem>
<groupId>jline</groupId>
<artifactId>jline</artifactId>
<version>2.10</version>
<type>jar</type>
</artifactItem>
<artifactItems>
<outputDirectory>../../resources/lib</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
<plugins>
<build>
And in assembly.xml
<fileSet>
<directory>../../resources/lib</directory>
<outputDirectory>${HOME}/lib/module1</outputDirectory>
<directoryMode>755</directoryMode>
<fileMode>644</fileMode>
<includes>
<include>jline-*</include>
</includes>
</fileSet>
jline-0.9.94 is included in a dependencySet as any other dependency.
I hope this helps. :)
Related
I have this maven multi-module project :
ModuleA
src
pom.xml
target
ModuleA-with-dependencies-shaded.jar (version 4.1 of lucene relocated)
ModuleB
src
pom.xml
target
ModuleB-with-dependencies.jar (version 7.5.0 of lucene)
ModuleDist
assembly
all.xml
pom.xml (shaded plugin for jar + assembly for Docker)
The dist pom plugins are configured like this :
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.2.2</version>
<configuration>
<shadedClassifierName>all</shadedClassifierName>
<shadedArtifactAttached>true</shadedArtifactAttached>
<transformers>
<!--remove models from jar see mitie -->
<transformer implementation="org.apache.maven.plugins.shade.resource.DontIncludeResourceTransformer">
<resource>.dat</resource>
</transformer>
</transformers>
<artifactSet>
<excludes>
<exclude>log4j:log4j:jar:</exclude>
</excludes>
</artifactSet>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<id>make-dist</id>
<goals>
<goal>single</goal>
</goals>
<configuration>
<descriptors>
<descriptor>src/assembly/all.xml</descriptor>
</descriptors>
</configuration>
</execution>
</executions>
</plugin>
And the assembly all.xml :
<assembly>
<id>all</id>
<formats>
<format>dir</format>
</formats>
<includeBaseDirectory>false</includeBaseDirectory>
<fileSets>
<fileSet>
<directory>${project.basedir}/src/main/docker</directory>
<outputDirectory>/</outputDirectory>
<includes>
<include>*</include>
</includes>
</fileSet>
<fileSet>
<directory>${project.build.directory}</directory>
<outputDirectory>lib</outputDirectory>
<includes>
<include>*.jar</include>
</includes>
</fileSet>
</fileSets>
</assembly>
As the ModuleA is having a transitive dependency on lucene 4.1 (but relocated so it won't clash with moduleB) and ModuleB is having a transitive dependency on lucene 7.5.0, I'd like to use the previously built and shaded jar of ModuleA in the maven shaded plugin of ModuleDist (because if I relocate lucene in ModuleDist it is relocating all lucene classes).
How could I do that ?
or is there another way of doing this ?
To add all your jars of the runtime dependencies to the assembly, add something like this:
<?xml version="1.0"?>
<assembly>
...
<dependencySets>
<dependencySet>
<outputDirectory>/lib</outputDirectory>
<unpack>false</unpack>
<scope>runtime</scope>
</dependencySet>
</dependencySets>
</assembly>
Take a look at the assembly plugin documentation for more details.
A working example can be found here (no shading used).
My personal experience is that it's better to only have one final module that assembles all stuff. This way the shader doesn't have to disassemble and assembler everything over and over.
Shading is a big problem when using Jackson and Log4j2 because it breaks some extension lookup mechanisms that expect everything to be in a separate jar. I recommend not using it anymore.
I have 2 projects, project A and project B. Project A is dependent on project B.
pom.xml of project A:
<dependencies>
<dependency>
<groupId>nft.dcs</groupId>
<artifactId>B</artifactId>
<version>0.0.1-SNAPSHOT</version>
</dependency>
</dependencies>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>3.1.1</version>
<configuration>
<appendAssemblyId>true</appendAssemblyId>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
<executions>
<execution>
<id>make-vision-plugin</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
<configuration>
<descriptors>
<descriptor>src/assembly/dep.xml</descriptor>
</descriptors>
</configuration>
</execution>
</executions>
</plugin>
Next, I compile my project and it creates a jar with all the dependencies that I don’t need. Created extra folders that do not have to be included in the jar file. I think these dependencies drag along with the dependency from project B.
Using the dep.xml file, I indicate which folders you do not need to include in the jar file.
dep.xml:
<id>with-spec</id>
<formats>
<format>jar</format>
</formats>
<includeBaseDirectory>false</includeBaseDirectory>
<dependencySets>
<dependencySet>
<outputDirectory>/</outputDirectory>
<useProjectArtifact>false</useProjectArtifact>
<unpack>true</unpack>
<unpackOptions>
<excludes>
<exclude>nft/**</exclude>
<exclude>com/**</exclude>
<exclude>impl/**</exclude>
<exclude>javax/**</exclude>
<exclude>junit/**</exclude>
<exclude>org/**</exclude>
<exclude>oshi/**</exclude>
<exclude>sound/**</exclude>
</excludes>
</unpackOptions>
<scope>runtime</scope>
</dependencySet>
</dependencySets>
<fileSets>
<fileSet>
<directory>${project.build.outputDirectory}</directory>
<outputDirectory>/</outputDirectory>
</fileSet>
</fileSets>
This method is just awful. Please tell me whether it is possible to add only classes from the dependency to the jar file and not to pull all these other folders.
You can try using scope provided:
<dependencies>
<dependency>
<groupId>nft.dcs</groupId>
<artifactId>B</artifactId>
<version>0.0.1-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
</dependencies>
You should take into account that, as maven documentation states:
indicates you expect the JDK or a container to provide the dependency at runtime
You are creating a jar with dependencies, probably to run it standalone.
So if A needs B, and B has dependencies on its own, A probably needs those as well to run. It is therefore sensible to pack all the dependencies of B into the runnable jar.
If B has unnecessary dependencies, these should be removed from B.
If B has dependencies, that for some reason are not required when A uses B, you should add a proper exclusion to the dependency in the POM.
I maintain a Java library which recently added support for CLI commands, but I'm having trouble understanding how to actually expose this support.
How can I provide an easy command cross-platform that works with all the dependencies needed?
During my own testing I have either relied on Junit tests that I run from IntelliJ or on the Maven exec plugin. IntelliJ and Maven manage all the dependencies, but I can't expect my library users to do the same. I'm thinking of providing a .bat file for Windows users and an alias for Linux users, which act as a shortcut for:
java -cp all;the;jars.jar my.package.CliSupportingClass command --option value
Is there a better way?
This article explains it quite well, using appassembler-maven-plugin to assemble all the dependencies and producing a script helper and maven-assembly-plugin to bundle it all as an archive such as zip and tar.
The article uses version 2.4 of one of the plugins, where I updated for the latest 3.1.0. The only difference for our use case is that the <descriptor> tag is now nested in a <descriptors> tag.
Include both plugins either as standard build plugins or under a profile:
<profiles>
<profile>
<id>standalone-cli</id>
<build>
<plugins>
<!-- appassembler-maven-plugin -->
<!-- maven-assembly-plugin -->
</plugins>
</build>
</profile>
</profiles>
The appassembler-maven-plugin collects all dependencies for us and produces a script helper for windows and unix:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>appassembler-maven-plugin</artifactId>
<version>1.8.1</version>
<configuration>
<repositoryLayout>flat</repositoryLayout>
<repositoryName>lib</repositoryName>
<showConsoleWindow>true</showConsoleWindow>
<platforms>
<platform>unix</platform>
<platform>windows</platform>
</platforms>
<programs>
<program>
<mainClass>org.simplejavamail.cli.SimpleJavaMail</mainClass>
<id>sjm</id>
</program>
</programs>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>assemble</goal>
</goals>
</execution>
</executions>
</plugin>
The maven-assembly-plugin then produces the archive(s):
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>3.1.0</version>
<configuration>
<descriptors>
<descriptor>src/assembly/standalone-cli-descriptor.xml</descriptor>
</descriptors>
</configuration>
<executions>
<execution>
<id>assemble-all</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
Finally standalone-cli-descriptor.xml tells maven-assembly-plugin what should be included in the archives and what type of archives should be produced:
<assembly
xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
<id>standalone-cli</id>
<formats>
<format>tar</format>
<format>zip</format>
</formats>
<includeBaseDirectory>false</includeBaseDirectory>
<fileSets>
<fileSet>
<directory>${project.basedir}</directory>
<outputDirectory>/</outputDirectory>
<includes>
<include>LICENSE-2.0.txt</include>
<include>NOTICE.txt</include>
<include>RELEASE.txt</include>
</includes>
</fileSet>
<fileSet>
<directory>${project.build.directory}/appassembler</directory>
<outputDirectory>/</outputDirectory>
<includes>
<include>**/**</include>
</includes>
</fileSet>
</fileSets>
</assembly>
Gradle has an application plugin that creates a distribution zip file. Your users can unzip this to install it. It has all the dependencies in a lib folder and Windows bat files and *nix shell scripts to run the application in a bin folder.
I believe Maven has something similar.
I know that it seems like a question that is already asked, but I have not found an answer that helps me a lot.
I read a lot of times that it is preferable to generate an artifact per project. But my question is : what can I have as a Maven artifact?
For example : I have a custom packaging "MyPack" with a custom lifecycle, can I have whole a directory "Mydirectory" as an artefact?
Let's say that the structure of the directory is like this:
MyDirectory
-----|--jars
-----|-----|--- client.jar
-----|-----|--- server.jar
-----|--jsps
-----|-----|--- page1.jsp
-----|-----|--- page2.jsp
-----|--imgs
-----|-----|--- img1.png
-----|-----|--- img2.png
Then, I want to create a new project that has the packaging "MyPack" and a dependency with the type "MyPack". In this project, my Java classes need client.jar and server.jar which are in the Maven repository to compile and I want to copy all jsps and imgs from the repository in my new project.
can I do all that with a custom Maven plugin?
You can have as maven artifact whatever you choose to have as an artifact.
Use the maven assembly plugin to generate the artifact:
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.4</version>
<configuration>
<descriptors>
<descriptor>${basedir}/src/main/assembly/shared.xml</descriptor>
</descriptors>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
....
</plugins>
....
</build>
In the shared.xml file you specify the format and files to be included in the artifact:
<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
<id>shared</id>
<formats>
<format>jar</format>
</formats>
<includeBaseDirectory>false</includeBaseDirectory>
<fileSets>
<fileSet>
<outputDirectory>/</outputDirectory>
<directory>${basedir}/.....</directory>
<includes>
<include> ... </include>
</includes>
<fileMode>0644</fileMode>
<filtered>false</filtered>
<lineEnding>unix</lineEnding>
</fileSet>
</fileSets>
</assembly>
When you do "maven deploy", the "shared" artifact will be packaged and deployed together with the project's main artifact.
In order to use the artifact in another project, use the maven-dependency-plugin with the goal "unpack-dependencies".
Is there a way to get an archive containing every dependency source as a separate artifact ?
What i know is that there is a way to download every source jar using the dependency-plugin as stated here. However these files are downloaded to the local repository.
What i try to achieve is:
Ship a JAR containing some runnable code. In addition a ZIP archive cotaining the source-code of shipped dependencies inside the JAR.
I needed to do something similar, except I also needed to filter the included sources to just those produced by teams at my company. You may use a combination of the maven-dependency-plugin and the maven-assembly-plugin to achieve this.
Here's the configuration I use.
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<configuration>
<overWriteReleases>false</overWriteReleases>
<overWriteSnapshots>true</overWriteSnapshots>
</configuration>
<executions>
<execution>
<id>retrieve-dependency-sources</id>
<phase>process-sources</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<classifier>sources</classifier>
<outputDirectory>${project.build.directory}/dep-sources</outputDirectory>
<type>jar</type>
<failOnMissingClassifierArtifact>false</failOnMissingClassifierArtifact>
<prependGroupId>true</prependGroupId>
<outputAbsoluteArtifactFilename>true</outputAbsoluteArtifactFilename>
<excludeTransitive>false</excludeTransitive>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<executions>
<execution>
<id>package-dependency-sources</id>
<phase>prepare-package</phase>
<goals>
<goal>single</goal>
</goals>
<configuration>
<appendAssemblyId>true</appendAssemblyId>
<attach>true</attach>
<finalName>${your.app.finalName}</finalName>
<descriptors>
<descriptor>src/main/assembly/dep-source-assembly.xml</descriptor>
</descriptors>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
And here is the assembly descriptor, dep-source-assembly.xml, which should be placed in src/main/assembly.
<assembly
xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.2 http://maven.apache.org/xsd/assembly-1.1.2.xsd">
<id>dep-sources</id> <!-- whatever you'd like the classifier to be -->
<formats>
<format>zip</format>
</formats>
<includeBaseDirectory>false</includeBaseDirectory>
<fileSets>
<fileSet>
<directory>${project.build.directory}/dep-sources</directory>
<outputDirectory></outputDirectory>
<!-- Define the includes if you'd like to have sources only for certain
packages. For my use case, I needed to include just source files
produced elsewhere in my company, not commonly available jars like
Spring. -->
<includes>
<include>**/com.mycompany.*.jar</include>
</includes>
</fileSet>
</fileSets>
</assembly>
It sounds like your use case may be a little different than mine, so you might be able to use the assembly plugin's dependencySet in place of the separate invocation of maven-dependency-plugin and the fileSet.
One other potential gotcha: if you are doing this for a war or ear, you will need to add a dependency on the project's POM to get the complete set of dependencies. (See MNG-1991.)
<dependency>
<groupId>${my.webapp.groupId}</groupId>
<artifactId>${my.webapp.artifactId}</artifactId>
<version>${my.webapp.version}</version>
<type>pom</type>
</dependency>