Creating Two Executable Jars Using maven-assembly-plugin - java

I have a Maven project and I want to create two executable jar files from it. One will be used interactively by users and a second will be run as a scheduled job that reads the log files produced by the former. In the end, I would expect the two jar files to be identical except for the Main-Class attribute in the MANIFEST.MF file.
I am using maven-antrun-plugin to create an executable jar and this seemed to be working fine until I tried to create a second jar file by introducing Maven profiles. The relevant section of my POM file looks like this:
<profiles>
<profile>
<id>publisher</id>
<build>
<finalName>${project.artifactId}</finalName>
<plugins>
...
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.4</version>
<configuration>
<appendAssemblyId>false</appendAssemblyId>
<finalName>${project.artifactId}</finalName>
<archive>
<manifest>
<mainClass>fully.qualified.path.Publisher</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
<profile>
<id>logReader</id>
<build>
<finalName>${project.artifactId}</finalName>
<plugins>
...
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.4</version>
<configuration>
<appendAssemblyId>false</appendAssemblyId>
<finalName>${project.artifactId}-logReader</finalName>
<archive>
<manifest>
<mainClass>fully.qualified.path.LogReader</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</profile>
</profiles>
Really, the only difference between the two is the "finalName" and "mainClass" elements as defined within the plugin.
When I try to execute mvn:package on both profiles (I'm using IntelliJ IDEA, by the way), I get two .jar files, but one is correct and the other is incorrect. The "correct" one contains all the dependencies and a valid MANIFEST.MF file. The "incorrect" one contains no dependencies and the MANIFEST.MF file lacks the "Main-Class" property that I need in order for it to be executable.
I have found that if I ever run just one profile or the other, that it works fine but, if I try to execute both profiles at once, it fails. I also get the following notes in my log, but I must admit that I don't completely understand what they are saying:
[INFO] Building jar: .../target/publisher.jar
...
[INFO] Building jar: .../target/publisher-logReader.jar
[WARNING] Configuration options: 'appendAssemblyId' is set to false, and 'classifier' is missing.
Instead of attaching the assembly file: .../target/publisher-logReader.jar, it will become the file for main project artifact.
NOTE: If multiple descriptors or descriptor-formats are provided for this project, the value of this file will be non-deterministic!
[WARNING] Replacing pre-existing project main-artifact file: .../target/publisher.jar with assembly file: .../target/publisher-logReader.jar
Any thoughts about this? Is it possible to produce two jar files with a single mvn:package in this way, or am I barking up the wrong tree?
Thanks!

So as soon as I posted this, I found this thread:
Create multiple runnable Jars (with depencies included) from a single Maven project
This uses a different approach in that it doesn't use two profiles, it uses two executions, as such:
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.4</version>
<executions>
<execution>
<id>build-publisher</id>
<configuration>
<appendAssemblyId>false</appendAssemblyId>
<archive>
<manifest>
<mainClass>fully.qualified.path.Publisher</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<finalName>${project.artifactId}</finalName>
</configuration>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
<execution>
<id>build-logReader</id>
<configuration>
<appendAssemblyId>false</appendAssemblyId>
<archive>
<manifest>
<mainClass>fully.qualified.path.LogReader</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<finalName>${project.artifactId}-logReader</finalName>
</configuration>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
This seems to be working. The moral of the story seems to be that I don't completely understand profiles or when they should be used.

Related

How do I exclude x.class from being compiled into my jar file?

I'm trying to make POM.xml generate two jar files. One with all the classes, the other excluding one of the classes.
The file i'm trying to exclude is named 'ExcludeMe1.java.'I'm new but it's not my FIRST rodeo, in the code below I've excluded ExcludeMe1.class. But the size of the jar file remains unchanged, and I believe it to still contain the class of which I am excluding. Here's what I mean...
<plugins>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
<configuration>
<appendAssemblyId>false</appendAssemblyId>
<archive>
<manifest>
<mainClass>com.costanzo.mavendemo.MavenDemo1</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
</execution>
<execution>
<id>make-assembly22</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
<configuration>
<excludes>
<exclude>${project.basedir}/target/excludeMe/ExcludeMe1.class</exclude>
</excludes>
<archive>
<manifest>
<mainClass>com.costanzo.mavendemo.MavenDemo1</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
What I expect to be happening is the exclusion of the class file, which size is 1KB. So instead of getting both jar's as size N I expect N, and N-1.
I am still really new to Maven, so hopefully yall can understand. Always ask questions if you need I'll be checking this thing frequently as it is a high priority project.
Excluding a single class using maven to my knowledge is not possible. Exclusion of jars is possible.
You can only exclude a jar file from the building process.

Eclipse built-in jar export option vs Maven assembly plugin

I use IntelliJ IDEA to generate a jar file with maven-assembly-plugin.
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>3.1.0</version>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
<configuration>
<archive>
<manifest>
<mainClass>test.LeanFTest</mainClass>
</manifest>
</archive>
<finalName>${project.artifactId}-fatjar-${project.version}</finalName>
<appendAssemblyId>false</appendAssemblyId>
</configuration>
</plugin>
It didn't work, it asks continuously for dependencies during execution. I was unable to use jar file, so I imported the project to Eclipse and used the built-in jar export option. This jar is working fine. I couldn't find what the difference is between these jar files.
The reason is probably that Eclipse is generating a "Class-Path:" entry in the manifest file.
Try to update the assembly conf in your .pom file by adding something like (by heart, not checked):
<addClasspath>true</addClasspath>
By default the maven-assembly-plugin will not bundle all the dependencies required for your own jar to run standalone.
So you will need to add this below under the plugin configuration:
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
As a result, the plugin tag becomes:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>3.1.0</version>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
<configuration>
<archive>
<manifest>
<mainClass>test.LeanFTest</mainClass>
</manifest>
</archive>
<finalName>${project.artifactId}-fatjar-${project.version}</finalName>
<appendAssemblyId>false</appendAssemblyId>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef> <!-- the secret -->
</descriptorRefs>
</configuration>
</plugin>
You can run:
java -jar path/to/LeanFTest.jar
To directly run the program.

Maven-assembly: how package only imported/used dependencies for each execution

I have a Maven project where I need to package different Java programs as jars, each one with its own dependecies.
To achieve this I am currently using maven-assembly-plugin with different executions, one for each java program I need to package (e.g. Program1.java, Program2.java, Program3.java):
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<executions>
<execution>
<id>assembly1</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
<configuration>
<archive>
<manifest>
<mainClass>my.package1.Program1</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<finalName>Program1</finalName>
<appendAssemblyId>false</appendAssemblyId>
</configuration>
</execution>
<execution>
<id>assembly2</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
<configuration>
<archive>
<manifest>
<mainClass>my.package2.Program2</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<finalName>Program2</finalName>
<appendAssemblyId>false</appendAssemblyId>
</configuration>
</execution>
<execution>
<id>assembly3</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
<configuration>
<archive>
<manifest>
<mainClass>my.package3.Program3</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<finalName>Program3</finalName>
<appendAssemblyId>false</appendAssemblyId>
</configuration>
</execution>
</executions>
</plugin>
Each one of these classes (Program1, Program2, Program3) requires different libraries as depedencies, thus I expected in output to get 3 jars with different size, but I got 3 files of the same size (Program1.jar, Program2.jar, Program3.jar).
It's like Maven is packaging all the dependencies defined inside the tag dependencies, regardless if they are used or not.
How can I tell maven to package, for each execution inside the assembly-plugin, only the dependencies effectively imported and used by the specified Class?
The default behaviour of assembly plugin is to include all dependencies of your current maven module. You could change that by explictly excluding the unwanted dependencies.
However, if you have three different programs that even do not have the same dependencies, it might be better to split up your project into three different (sub-)modules, maybe with a common parent pom. More details can be found here. After splitting up the project, each submodule can run its own assembly plugin that only packs the dependencies that are declared for each submodule.
If you decide to split up your project, you can clean up the required dependencies for each sub-module with the help of the dependency plugin, goal dependency:analyze.

eclipse source folder containing images doesn't export to JAR

I have written a Java program, when it is run I add the name of every image file in the folder "items" into an ArrayList.
This is fine when I am running the application in eclipse.
But as soon as I export to a runnable JAR file and run it, the images can't be found and returns a NullPointerException.
I've tried to use getClass().getResource() but to no avail.
This is what my Package Explorer looks like and
This is what my exported JAR looks like
As you can see from the second image, all the images are taken out of the items folder and left in the root of the JAR.
Any help would be greatly appreciated!
try maven-assembly-plugin if you are using the maven build tool
How can I create an executable JAR with dependencies using Maven?
https://www.mkyong.com/maven/create-a-fat-jar-file-maven-assembly-plugin/
Put this in your pom.xml
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.6</version>
<configuration>
<archive>
<manifest>
<mainClass>com.maven.class... (Class path)</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>2.1</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>

appassembler-maven-plugin vs maven-assembly-plugin

I have a appassembler-maven-plugin in my pom file and it used to work just fine - I can create a deployable package foe both windows and unix by running mvn assembly:assembly.
However it stop working for the new Spring boot project, complaining:
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-assembly-plugin:2.6:single (default) on project rest: Failed to create assembly: Error creating assembly archive bin: You must set at least one file. -> [Help 1]
what went wrong? and what's difference b/w appassembler-maven-plugin and maven-assembly-plugin? I tried the latter, it seems throwing the same error (I don't recall the error details for that).
the plugin in my pom looks like:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>appassembler-maven-plugin</artifactId>
<version>1.3</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>assemble</goal>
</goals>
</execution>
</executions>
<configuration>
<configurationSourceDirectory>src/main/resources</configurationSourceDirectory>
<configurationDirectory>config</configurationDirectory>
<copyConfigurationDirectory>true</copyConfigurationDirectory>
<includeConfigurationDirectoryInClasspath>true</includeConfigurationDirectoryInClasspath>
<assembleDirectory>${project.build.directory}/${project.name}</assembleDirectory>
<extraJvmArguments>
-Xms128m -Xmx128m
</extraJvmArguments>
<platforms>
<platform>unix</platform>
</platforms>
<programs>
<program>
<mainClass>com.mycompany.Application</mainClass>
<name>gs_rest.sh</name>
</program>
</programs>
</configuration>
</plugin>
For those hitting this page from a search engine:
The appassembler-maven-plugin is abandoned since 2015.
Please use the maven-assembly-plugin.
Below are 2 examples - with an explicit descriptor file, and one relying on a pre-defined descriptor.
<!-- The executable JAR(s) -->
<plugin>
<groupId>org.apache.maven.plugins</groupId><artifactId>maven-assembly-plugin</artifactId><version>3.4.2</version>
<executions>
<execution>
<id>assembleDistZip</id><goals><goal>single</goal></goals><phase>package</phase>
<configuration>
<finalName>${project.artifactId}-${project.version}-dist</finalName>
<archive>
<manifest>
<mainClass>${mainClass}</mainClass>
<addClasspath>false</addClasspath>
<classpathPrefix>lib/</classpathPrefix>
</manifest>
</archive>
<descriptors><descriptor>src/build/assembly-dist.xml</descriptor></descriptors>
</configuration>
</execution>
<execution><phase>package</phase><goals><goal>single</goal></goals>
<configuration>
<appendAssemblyId>false</appendAssemblyId>
<finalName>${project.artifactId}</finalName>
<outputDirectory>${project.build.directory}/dist</outputDirectory>
<descriptorRefs><descriptorRef>jar-with-dependencies</descriptorRef></descriptorRefs>
<archive>
<manifest> <!-- Jar - MANIFEST.MF options. -->
<addClasspath>false</addClasspath>
<mainClass>${mainClass}</mainClass>
<classpathPrefix>lib/</classpathPrefix>
</manifest>
<manifestEntries>
<Release-Version>${project.version}</Release-Version>
</manifestEntries>
</archive>
</configuration>
</execution>
</executions>
</plugin>

Categories