How add local dependecy in assembly JAR - maven

I have a multimodule Maven project with several dependencies. I want to build a fat executable JAR containing them as well as my own compiled classes. I found maven-assembly-plugin to be just what I needed except one nasty problem.
Some of my dependencies are local and distributed with project sources. I use system scope for them. It looks something like this:
<dependency>
<groupId>com.intellij</groupId>
<artifactId>forms_rt</artifactId>
<version>1</version>
<scope>system</scope>
<systemPath>${project.basedir}/lib/forms_rt.jar</systemPath>
</dependency>
The problem is that for some reason these libraries aren't unpacked and bundled with the rest of dependencies in result JAR.
I know that usage of system scope is considered bad practice, and in fact I even can find some of them (though quite outdated) in Maven repositories, but anyway it puzzles me how it can be solved with maven-assembly-plugin.
Just in case my plugin configuration looks like this:
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<archive>
<manifest>
<mainClass>repoll.server.Repoll</mainClass>
</manifest>
</archive>
<finalName>${project.build.finalName}-full</finalName>
<appendAssemblyId>false</appendAssemblyId>
<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>
As I understood I have to write custom descriptor, which e.g. includes and unpacks all JARs from ${project.basedir}/lib directory, but after several unsuccessful attempts I still don't know how to do so.

I've managed to find solution here. It's described in this question.
In short, the whole problem was in usage of system scope. It turned out, that such dependencies are filtered out by default, which I found out by running mvn package with debug output enabled (-X/--debug).
When local repository is defined for these JARs, distributed with project, they are unpacked by maven-assembly-plugin as exepected.

Related

Simple Java Mail dependencies not in the jar file

I used simplejavamail in my maven project. The program can send out the email if I run it from Intellij IDE. But when I create a jar file, and run it from the jar file, then I got class not found for all the simplejavamail classes. And I open the jar, I find out that they are not included in the jar. But all the other dependency classes are there. Any one have meet this issue before?
parts of my pom.xml
<dependency>
<groupId>org.simplejavamail</groupId>
<artifactId>simple-java-mail</artifactId>
<version>6.4.3</version>
</dependency>
<build>
<finalName>my-project-name</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<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>
</plugins>
</build>
I'm having the same problem. It appears that the dependencies (Ex. Email, Mailer, EmailBuilder, etc) appear in the org.simplejavamail.api repository. I'll update you if I find a working solution with v6.4.3 but I have a feeling we may need to include additional dependencies.
Edit: To at least patch your problem,
<dependency>
<groupId>org.simplejavamail</groupId>
<artifactId>simple-java-mail</artifactId>
<version>5.5.1</version>
</dependency>
The 5.5.1 version still has the classes in the jar. You can reference this for yourself here:
https://www.javadoc.io/doc/org.simplejavamail/simple-java-mail/5.5.1/index.html
Then click on the different versions to see what classes exist.
I think something went wrong in their builds since v6.
Let me know if this helps!

how to generate additional jar which having correct and complete manifest file for Bamboo deployment?

Basically, I want to generate a jar file named <project.name>.jar in addition to default jar file(which in my case is something like <project.name> + <project.version>.jar). NOTICE : This <project.name>.jar is all the same to default jar but the name.
And this additional jar should have a manifest file like below which is the manifest file of default generated jar
anifest-Version: 1.0
Archiver-Version: Plexus Archiver
Built-By: XXX
Start-Class: com.XXXX.XXX.Application
Spring-Boot-Version: 1.3.1.RELEASE
Created-By: Apache Maven
Build-Jdk: 1.8.0_74
Main-Class: org.springframework.boot.loader.JarLauncher
I am adding additional block in my as follows
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<executions>
....
<execution>
<id>copy-jar</id>
<phase>package</phase>
<goals><goal>jar</goal></goals>
<configuration>
<finalName>${project.name}</finalName>
</configuration>
</execution>
<execution>
</plugin>
But in my case, the manifest file generated in my addition jar don't have following impart fields:
Start-Class
Main-Class
...
So it couldn't be deployed.
I know the requirement sounds weird, but the question is clear, how to make maven generate a jar which having a correct and complete manifest file for deployment?
//The complete plugin part
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<executions>
<execution>
<goals><goal>test-jar</goal></goals>
</execution>
<execution>
<id>copy-jar</id>
<phase>package</phase>
<goals><goal>jar</goal></goals>
<configuration>
<finalName>${project.artifactId}</finalName>
</configuration>
</execution>
<execution>
<id>dto-jar</id>
<goals><goal>jar</goal></goals>
<phase>package</phase>
<configuration>
<finalName>${project.artifactId}-dto</finalName>
<includes>
<include>**/dto/*</include>
<include>**/dto</include>
<include>**/exceptions/*</include>
<include>**/exceptions</include>
<include>**/utils/*</include>
<include>**/utils</include>
</includes>
</configuration>
</execution>
</executions>
</plugin>
Concerning your maven-jar-plugin section:
You are having three executions: one for the test-jar goal, two for the jar goal
one of them re-using the default execution id (default-jar) to specify the finalName entry, but not specifying any manifest configuration. According to this configuration, your manifest file should also be empty then, not coherent with the description provided by your question then.
the additional jar goal execution has a further configuration with customizated option, nothing wrong here, except that you except to have a properly filled manifest file as part of it, while (again) there is no configuration for it.
A possible explanation would be that your pom also provides a pluginManagement section, with further configuration for the maven-jar-plugin, or a parent pom at its top which would then specify a further configuration for the same.
To double check this, you could run
mvn help:effective-pom -Doutput=eff-pom.xml
And check the content of the generated eff-pom.xml file. That would be the single source of truth for your case.
Looking at your manifest entry:
Spring-Boot-Version: 1.3.1.RELEASE
Main-Class: org.springframework.boot.loader.JarLauncher
It makes quite clear that you are working on a Spring Boot project, normally having a Spring Boot parent pom which already configures the required manifest file. However, it makes use of a fat-jar (jar with dependencies or uber jar), not built via the maven-jar-plugin but via the maven-assembly-plugin.
As an example:
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.4</version>
<configuration>
<descriptors>
<descriptor>src/main/assembly/jar-with-dependencies.xml</descriptor>
</descriptors>
<archive>
<manifest>
<mainClass>org.springframework.boot.loader.JarLauncher</mainClass>
</manifest>
<manifestEntries>
<Start-Class>org.springframework.boot.load.it.jar.EmbeddedJarStarter</Start-Class>
</manifestEntries>
</archive>
</configuration>
<executions>
<execution>
<id>jar-with-dependencies</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
Hence you should not look at the Jar Plugin solution, but rather add a further Assembly Plugin execution for the same.
Just quick share of some other aspects of this problem. actually pom file should never be in charge of deployment business(even though It could, but very likely bring into more issues in the future). This part should be fully managed by bamboo deploy script. That is what I eventually did.

Difficulty deploying second artifact with Maven

A mavenized version of an old project of mine creates two Jar files, one for command line and one for GUI use. As it currently stands, it deploys only the primary artifact to the local repository. The jars are created by having two executions for maven-jar-plugin, and both get created in the target directory. What happens is the GUI file overwrites the primary one, with the wrong name:
[INFO] Installing /Users/gmcgath/DevProjects/git/jhove/target/jhove-GUI-1.12.0-SNAPSHOT.jar to /Users/gmcgath/.m2/repository/edu/harvard/hul/ois/jhove/1.12.0-SNAPSHOT/jhove-1.12.0-SNAPSHOT.jar
I'm trying to use the build-helper plugin to get the GUI jar deployed to the repository, using the following:
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>build-helper-maven-plugin</artifactId>
<version>1.5</version>
<executions>
<execution>
<id>attach-artifacts</id>
<phase>package</phase>
<goals>
<goal>attach-artifact</goal>
</goals>
<configuration>
<artifacts>
<artifact>
<file>${project.artifactId}-GUI-${project.version}</file>
<type>jar</type>
<classifier>gui</classifier>
</artifact>
</artifacts>
</configuration>
</execution>
</executions>
</plugin>
Maven runs to completion without any errors, but doesn't copy the jar properly. The log tells me it's trying to copy the GUI jar from the project-level directory instead of the target to the correct destination. The GUI file is still overwriting the primary jar.
[INFO] Installing /Users/gmcgath/DevProjects/git/jhove/jhove-GUI-1.12.0-SNAPSHOT to /Users/gmcgath/.m2/repository/edu/harvard/hul/ois/jhove/1.12.0-SNAPSHOT/jhove-1.12.0-SNAPSHOT-gui.jar
(The "harvard" part is historical. Keeping this open-source project was part of my severance package. :)
So I'm doing something basically wrong. How can I fix this? Should I be using the assembly plugin instead, even though it looks more complicated?
Update: Partially fixed. The file element in the artifact needs to be
<file>${project.build.directory}/${project.artifactId}-GUI-${project.version}.jar</file>
I'm still looking for the fix to get the primary artifact copied correctly.
OK, here's my fix. The first part, as indicated above, was to get the directory and extension right in the build-helper artifact. It should have been
<file>${project.build.directory}/${project.artifactId}-GUI-${project.version}.jar</file>
The other issue was in a part of the pom.xml that I didn't post. The two executions lacked a classifier element, and so looked like this:
<executions>
<execution>
<!-- console app - don't change id, will cause build problems -->
<id>default-jar</id>
<phase>package</phase>
<goals><goal>jar</goal></goals>
<configuration>
<classifier>cmd</classifier>
<archive>
<manifest>
<mainClass>Jhove</mainClass>
</manifest>
</archive>
</configuration>
</execution>
<execution>
<id>gui-app-jar</id>
<phase>package</phase>
<goals><goal>jar</goal></goals>
<configuration>
<classifier>gui</classifier>
<archive>
<manifest>
<mainClass>JhoveView</mainClass>
</manifest>
</archive>
<finalName>${project.artifactId}-GUI-${project.version}</finalName>
</configuration>
</execution>
</executions>
Everything looks OK now.

Unable to disable generation of empty JAR (maven-jar-plugin)

Sometimes, my Talend Open Studio components have resources but not Java sources (they are purely metadata components). I need to disable the generation of JAR files in such a case.
I configured the maven-jar-plugin this way:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.4</version>
<configuration>
<forceCreation>false</forceCreation>
<skipIfEmpty>true</skipIfEmpty>
<useDefaultManifestFile>false</useDefaultManifestFile>
</configuration>
</plugin>
but I still get the ${project.name}.jar file with pom.properties, pom.cml, the manifest and an empty file App.class containing only "class {}"
While I can disable the includes of all maven stuff using this:
<archive>
<addMavenDescriptor>false</addMavenDescriptor>
</archive>
I still get a JAR with the manifest file inside it
Are there some configuration parameters I misconfigured?
Most efficient way to disable the creation of jars is to configure the maven-jar-plugin like this:
<plugins>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<version>2.3.1</version>
<executions>
<execution>
<id>default-jar</id>
<phase>none</phase>
</execution>
</executions>
</plugin>
</plugins>
It will place the default jar creation in the none phase, it will never be run.
I found the solution by myself, even if it's only a workaround. I delete the JAR using a delete antrun task if /src/main/java directory doesn't exist:
<!-- remove the empty JAR if not needed -->
<if>
<not><available file="${basedir}/src/main/java" type="dir" /></not>
<then>
<delete file="${project.build.directory}/${project.name}-${project.version}.jar"/>
</then>
</if>
this task requires antcontrib to work properly and, ofc, it doesn't work if you plan to do releases with maven (but it's ok for metadata-only components, like Talend Open Studio plugins)
You can instruct maven-jar-plugin to not generate META-INF/maven/*/pom. files, as explained in Maven Archiver Reference.
Also, you can use its skipIfEmpty option.
Following code combines both these (just to have them copy-paste ready):
...
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jar-plugin</artifactId>
<version>2.4</version>
<configuration>
<skipIfEmpty>true</skipIfEmpty>
<archive>
<addMavenDescriptor>false</addMavenDescriptor>
</archive>
...
This works fine, but when you do mvn install, it fails due to missing project artifact.
Similar problem will probably be with mvn deploy and with release, but I didn't check these.
However, if you can live with antrun's delete, the property skipIfEmpty will probably work well for you, and is a bit more elegant. At least it does not introduce a new execution and its dependencies etc.

Client JAR containing maven dependencies

I'm building a service which contains a client module which is using Spring. The service which will be implementing the client does not contain spring but it has a dependency on the client which has dependencies on Spring. Ideally I would like the client to include the needed Spring dependencies in the JAR but I can't seem to figure out how to accomplish this. I've seen a few different examples of using maven-assembly-plugin but I would prefer to not have to use something other than "mvn clean package" to accomplish this.
Any help is appreciated.
The maven-shade-plugin allows you to build an uber-jar containing some (or all) of your dependencies. It should allow you to do what you need.
By binding the assembly plugin's single goal to the project's build lifecycle, you can accomplish what you want by running mvn clean package.
Cut/pasting the pom configuration to do this from the usage page of the plugin,
<project>
[...]
<build>
[...]
<plugins>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.2.2</version>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
<executions>
<execution>
<id>make-assembly</id> <!-- this is used for inheritance merges -->
<phase>package</phase> <!-- bind to the packaging phase -->
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
[...]
</project>
Of course, you would tweak either either to use a different predefined descriptor or even use a separate descriptor file.

Resources