maven, deploy a desktop application - java

I am switching from ant to maven.
To keep things simple, my application is a swing application that connects to a database.
I want it to be packaged in a jar file.
The application requires an external library, that is Microsoft sql server library, contained in a jar file: sqljdbc4-3.0.jar.
So i tryed to include this library:
<dependency>
<groupId>com.microsoft.sqlserver</groupId>
<artifactId>sqljdbc4</artifactId>
<version>3.0</version>
</dependency>
but when launching the jar, i get the exception:
java.lang.SecurityException: Invalid signature file digest for Manifest main attributes
This problem is already documented in other stackoverflow questions; i'm talking of this just to get to the point.
My idea (maybe naive) is the following, i would like to
create a jar with only my code.
create a distribution that contains in a directory (lib) all my libraries.
the manifest file to correctly reference all the libraries.
Searching around, i've found that each one of this issues is performed by a different maven plugin: jar plugin, dependency plugin and assembly plugin.
Is this the way to go? I don't feel it right because i've undesrtood that maven would handle easily "regular" configurations and this solutions of the three plugins seems a bit over-complex.

You need to add these plugins to pom
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifest>
<addClasspath>true</addClasspath>
<classpathPrefix>lib</classpathPrefix>
</manifest>
</archive>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>2.4</version>
<configuration>
<descriptor>src/main/assembly/assembly.xml</descriptor>
</configuration>
</plugin>
src/main/assembly/assembly.xml
<assembly>
<id>assembly</id>
<formats>
<format>zip</format>
</formats>
<dependencySets>
<dependencySet>
<outputDirectory>/lib</outputDirectory>
<unpack>false</unpack>
</dependencySet>
</dependencySets>
</assembly>
run assembly
mvn clean package assembly:single

This is the maven way. By the way: the jar plugin and the dependency plugin are included always in a maven build and there should be no need to configure them.
Additionally a good help could be the appassembler that creates a distributable including all jar files needed.

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)

Maven: how to do runable jar (uberjar) with included external libraries

Until now i made runnable jars with Ant and there were no problems with it.
However i now try to mavenize my project and i realy can't figured out how to do runable jar with this tool.
I've read tons of tutorials (also here, on Stackoverflow), helps, advices and... nothing. In my case all of them don't work which probably means i don't understand some basics.
I have such simple project:
This is app, witch use mysql-connector-java-5.1.24-bin.jar (placed in 'lib' dir) to connect to MySQL database.
I want to include this jar into final jar (DBPreformatter.jar).
I used assembly and shaded plugins in many configurations, but they NEVER added this jar into DBPreformatter.jar.
This is my pom.xml:
<modelVersion>4.0.0</modelVersion>
<groupId>com.icd4you</groupId>
<artifactId>DBPreformatter</artifactId>
<version>1.0.0</version>
<name>DBPreformatter</name>
<description>DB processing and cleaning tool</description>
<packaging>jar</packaging>
<dependencies>
<dependency>
<groupId>mysql-connector-java-5.1.24-bin</groupId>
<artifactId>mysql-connector-java-5.1.24-bin</artifactId>
<version>5.1.24</version>
<scope>system</scope>
<systemPath>${basedir}/lib/mysql-connector-java-5.1.24-bin.jar</systemPath>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.7</source>
<target>1.7</target>
</configuration>
</plugin>
<!-- WHAT SHOULD I USE HERE? -->
</plugins>
</build>
How to solve this problem?
There is a maven plugin Apache Maven Shade Plugin that will build an uber jar for you
Add the Maven Assembly plugin with the descriptor jar-with-dependencies:
<build>
<plugins>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
<archive>
<manifest>
<mainClass>com.pany.your.MainClass</mainClass>
</manifest>
</archive>
</configuration>
<executions>
<execution>
<id>make-assembly</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
</plugin>
Note that this doesn't add the JAR; instead it unpacks all JARs which are listed as dependencies and adds their content to the resulting JAR (so you'll see all the class files from the MySQL JAR in the result instead of the MySQL JAR itself).
EDIT There is a caveat, though: Maven ignores JARs with scope=system for many operations. See also: How to include external jars in maven jar build process?
If Maven doesn't add the JAR to the output, then you must install all JARs with this scope into your local maven repo ($HOME/.m2/repository) using the mvn install:file-install command. See http://maven.apache.org/plugins/maven-install-plugin/usage.html how to do that.
Note: Installing libraries in your local repo is the preferred way; you should really consider it. For one, the scope=system will no longer confuse you (since many plugins handle them in a special way). Plus you need to do this only once. Afterwards, you can use this library in many Maven projects.
Before installing, you should check http://search.maven.org/ to see if the dependency isn't already known to Maven.
MySQL is: http://search.maven.org/#artifactdetails%7Cmysql%7Cmysql-connector-java%7C5.1.32%7Cjar

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.

Insert a dependent jar into an installer jar

I have a multi-module maven project with an installer sub-project. The installer will be distributed as an executable JAR. It will setup the DB and extract the WAR file to the app server. I would like to use maven to assemble this jar like so:
/META-INF/MANIFEST.MF
/com/example/installer/Installer.class
/com/example/installer/...
/server.war
The manifest will have a main-class entry pointing to the installer class. How might I get maven to build the jar in this fashion?
You can build the jar using the Maven Assembly Plugin.
First, you'll need to add some information to your pom.xml plugins section to make the resulting jar executable:
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<archive>
<manifest>
<mainClass>com.example.installer.Installer</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
I recommend using a separate assembly descriptor to build the actual installer jar. Here's an example:
<assembly>
<id>installer</id>
<formats>
<format>jar</format>
</formats>
<baseDirectory></baseDirectory>
<dependencySets>
<dependencySet>
<outputDirectory>/</outputDirectory>
<includes>
<!-- this references your installer sub-project -->
<include>com.example:installer</include>
</includes>
<!-- must be unpacked inside the installer jar so it can be executed -->
<unpack>true</unpack>
<scope>runtime</scope>
</dependencySet>
<dependencySet>
<outputDirectory>/</outputDirectory>
<includes>
<!-- this references your server.war and any other dependencies -->
<include>com.example:server</include>
</includes>
<unpack>false</unpack>
<scope>runtime</scope>
</dependencySet>
</dependencySets>
</assembly>
If you've saved the assembly descriptor as "installer.xml" you can build your jar by running the assembly like this:
mvn clean package assembly:single -Ddescriptor=installer.xml
Hope this helps. Here are some additional links that you might find useful:
Maven Assembly Plugin - Configuration and Usage
Creating Executable JARs using the Maven Assembly Plugin
Creating executable jars with Maven

Categories