Adding content files to a Maven artifact - java

I create an artifact with maven and I want to add some content files to the target consumer beside the jar file. (I want to add some Jenkins scripts, but I want these scripts to get updated when the consumer upgrades into newer version of the artifact).
This is similar to .net nuget, where you can add a content library to the consumer project.
According to #tashkhisi suggestion I'm trying Maven assembly plugin.
The project structure:
> pipline (folder)
>>> file1.groovy (file)
>>> file2.groovy (file)
>>> file3.groovy (file)
> src (folder)
>>> ...
> assembly (folder)
>>> distribution.xml (file)
> pom (file)
In the pom file:
...
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.4.1</version>
<configuration>
<descriptors>
<descriptor>assembly/distribution.xml</descriptor>
</descriptors>
</configuration>
<executions>
<execution>
<id>trigger-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</build>
The assembly/distribution.xml looes like that:
<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/2.4.1"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/2.4.1">
<id>distribution</id>
<formats>
<format>jar</format>
</formats>
<fileSets>
<fileSet>
<directory>${basedir}/pipeline</directory>
<includes>
<include>*.groovy</include>
</includes>
<excludes>
<exclude>file2.groovy</exclude>
</excludes>
</fileSet>
</fileSets>
<files>
<file>
<source>pipeline/file2.groovy</source>
<outputDirectory></outputDirectory>
<filtered>true</filtered>
</file>
</files>
</assembly>
I can see in the target folder that two jar files are created:
target/myLib-1.1.0-SNAPSHOT.jar
target/myLib-1.1.0-SNAPSHOT-distribution.jar
But when I try to consume it from another project the pipeline folder with the groovy files is not getting created...

In your configuration you said pipeline is beside src and in your pom.xml you define outputDirectory as <outputDirectory>${basedir}/pipeline</outputDirectory> which is exactly beside src(pipeline is already there!) so if you want to put this pipeline directory beside target jar file in target directory you should modify this configuration to something like this:
<outputDirectory>${basedir}/target/pipeline</outputDirectory>
By the way creating a zip file which contains all the thing that you need in your deployment using assembly plugin is better approach, read the following link:
https://maven.apache.org/plugins/maven-assembly-plugin/

This is not possible.
Adding something as dependency will not add or create any folders in your project.
The consumer will need to add logic to the project to extract files from the dependency and copy them to the right place (probably possible with the Maven dependency plugin).

Related

Pack library and all its dependencies to one folder, but other dependencies in separate folder

I've maven project. I use maven-assembly-plugin to create zip files with all module dependencies packed in it.
Need to create zip with following structure:
/my-libs
/other-libs
To my-libs need to pack dependencies from my-lib depenency + all its transitive dependencies.
TO other-libs need to pack all other dependencies from current maven module.
Basically I need conditionally select target folder:
if (dependency in transitive-dependencies(my-lib))
copy to /my-libs
else
copy to /other-libs
Is it possible to do with maven-assembly-plugin ? Are there any alternative maven plugins to do so?
You need to define two dependencySet in the assembly XML file
<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">
...
<dependencySets>
<dependencySet>
<useProjectArtifact>false</useProjectArtifact>
<useTransitiveFiltering>false</useTransitiveFiltering>
<includes>
<include>com.example:dependency1:jar</include>
<include>com.example:dependency2:jar</include>
...
</includes>
<outputDirectory>/my-libs</outputDirectory>
</dependencySet>
<dependencySet>
<useProjectArtifact>false</useProjectArtifact>
<useTransitiveFiltering>false</useTransitiveFiltering>
<includes>
<include>com.example:other1:jar</include>
<include>com.example:other2:jar</include>
...
</includes>
<outputDirectory>/other-libs</outputDirectory>
</dependencySet>
</dependencySets>
...
</assembly>
Docs:
http://maven.apache.org/plugins/maven-assembly-plugin/usage.html
http://maven.apache.org/plugins/maven-assembly-plugin/assembly.html
I got the impression that you started the wrong way. You say that only some programs need other-libs on the classpath, others not. So these seem not to be "real" dependencies of your project, at most optional ones.
I would suggest to use the my-lib project to create an assembly zip of my-lib with all dependencies. This can be used in all contexts where otherlibs are not necessary.
On the other hand, you can create a second zip from your original project, containing all the libs. This way, you have two different zips for two different purposes, but you do not need to create a directory structure inside the zip.
You can split your dependencies into two modules:
- ModuleX
pom.xml (contain my-libs)
- ModuleY
pom.xml (contain my-libs + other-libs)
Then use maven-dependency-plugin to copy transitives dependencies into respective folder.
<build>
<plugins>
<plugin>
<artifactId>maven-dependency-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<outputDirectory>${project.parent.basedir}/build/other-lib</outputDirectory>
<includeScope>runtime</includeScope>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
Now you each module build will contains exactly only the jars you need, no duplicate INSIDE. (I think we can ignore the duplication of my-libs BETWEENboth build because you don't gonna use both in the same platform anyway)

Project depedencies in Eclipse m2e multiproject vs. package with manifest

I am finishing migrating a standalone multi-project java from Ant to Maven. The structure of my projects is similar to the following:
parent-project
|_ Project A
| |
|_Project B
|_Project C
In parent-project there is no code but I define in the DependencyManager the most common used dependencies and their versions. ProjectA POM uses the depedencies defines in parent-project and ProjectB too and calls methods from ProjectA.
I can perfectly execute my desktop application from Eclipse as a Maven project (Goals: exec:java). The Dependency Hierarchy tab provided by m2e shows the right dependency order and it's the same shown as dependency:build-classpath.
dependency:build-classpath tells Maven to output the path of the dependencies from the local repository in a classpath format to be used in java -cp. The classpath file may also be attached and installed/deployed along with the main artifact.
However, despite my project depedencies seems correct when I launch the standalone application as a Maven main project from Eclipse, it is not the same when I package the jar with its jar dependencies in a sub-directory (created with maven-jar-plugin).
MyApp.jar
|_ \lib
|_ MyApp dependencies
|_ Maven projects jars
|_ Maven projects jars dependencies
My manifest file include a classpath that is the equivalente to execute "mvn dependency:resolve" but I still don't manage to figure out where the order of these jars come from (even changing the POM doesn't seem to have any effect on it). My application manage to run but I have many problem with runtime libraries because it doesn't use the one that it is meant to use.
dependency:resolve tells Maven to resolve all dependencies and displays the version
If there is someone out there that could point out the source of this problem, I would be eternally greatful.
I have found myself the solution after all.
The problem appeared only when invoking maven-dependency-plugin for copying the dependencies. I remove the execution of that plugin and replace the copy-resource with maven-resources-plugin.
Before (not working):
<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>jar-with-dependencies</id>
<formats>
<format>dir</format>
</formats>
<!-- Dependencies properties -->
<dependencySets>
<dependencySet>
<outputDirectory>lib</outputDirectory>
<useProjectArtifact>false</useProjectArtifact>
<unpack>false</unpack>
</dependencySet>
</dependencySets>
<!-- To avoid include the target name as a root directory -->
<includeBaseDirectory>false</includeBaseDirectory>
<fileSets>
<!-- Copy resources from resources to target -->
<fileSet>
<directory>../AnotherJavaProject/src/main/resources/utils/</directory>
<outputDirectory>utils</outputDirectory>
</fileSet>
<!-- ...more resources here -->
<!-- Copy the .exe to the target folder -->
<fileSet>
<directory>${project.build.directory}</directory>
<outputDirectory></outputDirectory>
<includes>
<include>*.exe</include>
</includes>
</fileSet>
</fileSets>
</assembly>
After (working):
<plugin>
<artifactId>maven-resources-plugin</artifactId>
<executions>
<execution>
<id>copy-resources</id>
<phase>package</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/${project.build.finalName}</outputDirectory>
<resources>
<resource>
<!-- Copy resources from resources to target --> <directory>../AnotherJavaProject/src/main/resources/utils/</directory>
<targetPath>utils</targetPath>
</resource>
<!-- ...more resources here -->
<!-- Copy the .exe to the target folder -->
<resource>
<directory>${project.build.directory}</directory>
<include>*.exe</include>
</resource>
</resources>
</configuration>
</execution>
</executions>
</plugin>
Hope this help somebody.

Maven : add external resources

I am building an executable jar file with maven, meaning that you run it with "java -jar file.jar".
I want to rely on user defined properties (just a file containing keys/values), during developpement phase I was putting my "user.properties" file in maven /src/main/resources/ folder.
My property file is loaded with:
final Properties p = new Properties();
final InputStream resource = IOParametres.class.getResourceAsStream("/user.properties");
p.load(resource);
Now, I want to keep that file outside of the JAR and have something like this :
- execution_folder
|_ file.jar
|_ config
|_ user.properties
I tried many things with maven plugins like maven-jar-plugin, maven-surefire-plugin and maven-resources-plugin but I can't get it working...
Thanks in advance for your help!
I found what I needed using only maven configuration.
First I add config folder to the classpath:
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.3.1</version>
<configuration>
<archive>
<manifestEntries>
<Class-Path>config/</Class-Path>
</manifestEntries>
</archive>
</configuration>
</plugin>
</plugins>
</build>
I load resources the same way as before:
final InputStream resource = IOParametres.class.getResourceAsStream("/user.properties");
p.load(resource);
And if you want to keep your example resource files in your repo and remove them from your build:
<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<excludes>
<exclude>user.properties</exclude>
<exclude>conf/hibernate.cfg.xml</exclude>
</excludes>
</resource>
</resources>
</build>
Next to the jar file, I add a config folder holding all the resource files I need.
The result is:
user.properties can be loaded using getResourceAsStream
other libraries relying on specific resources (I won't argue, but I find it... not that good) can load their resources without any issue.
Thanks for the help, and I hope it may help somebody someday!
As I mentioned in the comment - it looks like you want to use user.properties file simply as a text file that lies besides your jar. If that's the case, than using it is rather simple - directory containing your jar file is the current directory when checked during runtime. That means that all you need is:
properties.load(new FileInputStream("config/user.properties"));
without trying to put in on the project classpath.
And if anything else is there to be done, it would just by copying your properties from resources directory to target to avoid the hussle of doing it by hand. That can be achieved by maven-antrun-plugin:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-antrun-plugin</artifactId>
<executions>
<execution>
<phase>generate-resources</phase>
<goals>
<goal>run</goal>
</goals>
<configuration>
<tasks>
<mkdir dir="${project.build.directory}" />
<copy file="${basedir}/src/main/resources/user.properties" tofile="${project.build.directory}/config/user.properties" />
</tasks>
</configuration>
</execution>
</executions>
</plugin>

Alternative to maven assembly:single for packaging

What are the alternatives for packaging a standalone java application apart from creating a big fat assembly, which is horrible in some scenarios as
1) Conflicting files (with same names eg. reference.xml) in resource path of two or more jars get overriden by the lucky one.
2) Replacing a single jar is not possible without extracting and merging and compressing again.
Is there a solution more on the lines of an exploded war file, with all the libs in a lib folder and main class file's jar containing manifest entries.
I am sure i had done that in ant and could surely be done in maven too.
Assembly plugin will be the good choice with a custom descriptor:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<descriptors>
<descriptor>assembly.xml</descriptor>
</descriptors>
</configuration>
</plugin>
And in the assembly.xml:
<assembly xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.0 http://maven.apache.org/xsd/assembly-1.1.0.xsd">
<id>bin</id>
<formats>
<format>tar.gz</format>
</formats>
<includeBaseDirectory>true</includeBaseDirectory>
<fileSets>
<fileSet>
<directory>${project.build.directory}</directory>
<outputDirectory>/</outputDirectory>
<includes>
<include>${project.artifactId}-${project.version}.jar</include>
</includes>
</fileSet>
</fileSets>
<dependencySets>
<dependencySet>
<outputDirectory>/lib</outputDirectory>
<useProjectArtifact>false</useProjectArtifact>
<unpack>false</unpack>
</dependencySet>
</dependencySets>
</assembly>
All the dependencies will be seperate jars in the lib directory next to the project jar file.
I tend to use Mojo's AppAssembler Maven Plugin to make a distribution and then use the Maven Assembly Plugin to wrap that all up into a tar.gz or zip file that comprises the distribution... sometimes I will go further and use Mojo's Unix Maven Plugin to create .deb and .rpm installers, and I have heard good things from people who need Windows installers using Mojo's NSIS Maven Plugin though NPanday's WiX Maven plugin should be able to do similar and previously when I needed to generate Windows installers I wrote my own WiX Maven plugin, but the source code for that remains with my previous employers.
If you go down the AppAssembler route, I would suspect you might prefer a repositoryLayout of flat

Is it possible to create an "uber" jar containing the project classes and the project dependencies as jars with a custom manifest file?

I'm trying to create a executable jar(using maven) that contains the project classes and it's dependencies with a manifest file that has the entry for the main class and the class path entry that points to the dependencies packed in the root of the jar;something like this :
Manifest File:
.....
Main-Class : com.acme.MainClass
Class-Path : dependecy1.jar dependecy2.jar
.....
Jar:
jar-root
|-- ....
|-- com/acme/../*.class
|-- dependecy1.jar
`-- dependecy2.jar
I'm using the maven-jar-plugin to create the manifest file and the maven-shade-plugin to create the "uber" jar but the dependencies are unpacked and added as classes to my jar.
Actually, I didn't check what the maven-shade-plugin is doing exactly (or any other plugin) as maven 2 has everything built-in to create a megajar or uberjar. You just have to use the maven-assembly-plugin with the predefined jar-with-dependencies descriptor.
Just add this snippet to your pom.xml to customize the manifest:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<archive>
<manifest>
<mainClass>my.package.to.my.MainClass</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
And the following command will generate your uberjar:
mvn assembly:assembly -DdescriptorId=jar-with-dependencies
But, again, the default behavior of this descriptor is to unpack dependencies (like the maven-shade-plugin). To be honest, I don't get why this is a problem but, if this is really not what you want, you can use your own custom assembly descriptor.
To do so, first, create your assembly descriptor, let's say src/assembly/uberjar.xml, with the following content:
<assembly>
<id>uberjar</id>
<formats>
<format>jar</format>
</formats>
<includeBaseDirectory>false</includeBaseDirectory>
<dependencySets>
<dependencySet>
<unpack>false</unpack>
<scope>runtime</scope>
<useProjectArtifact>false</useProjectArtifact>
</dependencySet>
</dependencySets>
<fileSets>
<fileSet>
<directory>${project.build.outputDirectory}</directory>
<outputDirectory>/</outputDirectory>
</fileSet>
</fileSets>
</assembly>
Then, configure the maven-assembly-plugin to use this descriptor and to add the dependencies to the Class-Path entry of the manifest:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<descriptors>
<descriptor>src/assembly/uberjar.xml</descriptor>
</descriptors>
<archive>
<manifest>
<mainClass>my.package.to.my.MainClass</mainClass>
<addClasspath>true</addClasspath>
</manifest>
</archive>
</configuration>
<!--
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
-->
</plugin>
Finally run mvn assembly:assembly to produce your uberjar.
Optionally, uncomment the executions element to bind the assembly plugin on the package phase (and have the assembly produced as part of the normal build).
OneJar has a maven2 plugin.
I've used FatJar for this in the past. http://fjep.sourceforge.net/
I had created a relatively simple application, the client was going to want to double click on an executable and have it just work. Installers or dependencies are out of the question. Fatjar bundled up the project libraries and referenced files from Eclipse into a several megabyte executable jar for me. Flawless.
task uberJar(type: Jar) {
manifest {
attributes 'Main-Class': 'main.RunTest'
}
dependsOn configurations.runtimeClasspath
from sourceSets.main.output
from sourceSets.test.output
from sourceSets.main.resources
from sourceSets.test.resources
from {
configurations.runtimeClasspath.findAll { it.name.endsWith('jar') }.collect { zipTree(it) }
}
from {
project(':someothermoudule').sourceSets.main.resources // If current project depends on some other modules
project(':someothermoudule').sourceSets.test.resources // If current project depends on some other modules
}
exclude 'META-INF/*.RSA'
exclude 'META-INF/*.SF'
exclude 'META-INF/*.DSA'
}
In case of gradle above can help. Note the from { project('')} lines, this is only required when the current project depends on some other sub projects or modules.

Categories