How to make a plugin-like architecture runnable? - java

We have a couple of legacy Java projects, which we converted to Maven projects / modules. Previously, all projects were NetBeans projects and had no real dependency management. External dependencies existed on the companies network drive and were directly included as JARs in the NetBeans projects of each module. For the internal dependencies, simple project references were used. It was a pain to build everything because the programmer had to build everything in the right order.
Now, we are in the position that we can open all the Maven modules in IntelliJ IDEA and NetBeans. However, I am having trouble figuring out the best way to combine the different modules and external dependencies in a specific way, which conforms to in-house plugin-like structure. Especially with NetBeans (developing with both IDEs must be possible).
Here is how the git repositories / project structure roughly looks like. The folder structure of the modules is the default Maven structure for each module. The list feature of this site was too clumsy, so I included it as screenshot...
We have an internal maven repository for the stuff and building with maven etc. is working. For Intellij IDEA i can run and debug the end product for customer1 via a custom run configuration, which copies the needed files in the needed structure:
With IntelliJ IDEA, I can debug the software, but I think that the approach (custom IntelliJ run config I created, pointing to all needed JARs and files directly) is rather ugly, and for NetBeans I could not find a similar "run configuration" mechanism.
So I tried to achieve this build process by creating a new "Customer1Runnable" Maven project as a sort of build description, which points to all needed Maven modules. Based on this, I believed I could achieve and automatism to create the needed software structure. Ergo copy all modules into a plugin folder and all dependencies of the modules into a lib folder inside the Customer1Runnable project, using the maven-assembly-plugin.
First off, is my assumption correct that this is a possible use case for the maven-assembly-plugin?
The project itself does not have any source files, it is only a pom.xml and the assembly-config.xml descriptor. I attached the assembly-plugin to the package phase. When running the mvn package command all connected modules are built, but for the execution of the assembly-plugin I get the following output:
For starters, I only tried to include one module in the assembly descriptor. This is the XML (opicom-assembly.xml) for it:
<assembly xmlns="http://maven.apache.org/ASSEMBLY/2.1.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/ASSEMBLY/2.1.0 http://maven.apache.org/xsd/assembly-2.1.0.xsd">
<id>opicom-assembly</id>
<formats>
<format>dir</format>
</formats>
<includeBaseDirectory>false</includeBaseDirectory>
<moduleSets>
<moduleSet>
<useAllReactorProjects>true</useAllReactorProjects>
<includes>
<include>my.company.reporting:module1</include>
</includes>
</moduleSet>
</moduleSets>
</assembly>
pom.xml of Customer1Runnable project
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<version>1.6</version>
<groupId>my.company.customer1</groupId>
<artifactId>OpicomRunnable</artifactId>
<packaging>pom</packaging>
<name>OpicomRunnable</name>
<repositories>
<repository>
<id>Company-Maven-Repo</id>
<url>file:\\\\MyCompany\TFSDrop\MavenRepo</url>
</repository>
</repositories>
<modules>
<module>../my.company.customer1.module1</module>
<module>../my.company.customer1.module2</module>
.
.
.
<module>../../MyCompany_Common/Report/my.company.reporting.module1</module>
</modules>
<build>
<plugins>
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<version>3.3.0</version>
<inherited>true</inherited>
<executions>
<execution>
<id>copy-dependencies</id>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
<configuration>
<descriptors>
<descriptor>opicom-assembly.xml</descriptor>
</descriptors>
</configuration>
</plugin>
</plugins>
</build>
</project>
The pom of a module looks like this:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>my.company</groupId>
<artifactId>reporting</artifactId>
<version>1.3</version>
<relativePath>../pom.xml</relativePath>
</parent>
<artifactId>module1</artifactId>
<version>1.3</version>
<packaging>jar</packaging>
<dependencies>
<!-- external dependencies -->
<dependency>
<groupId>commons-pool</groupId>
<artifactId>commons-pool</artifactId>
<version>1.6</version>
</dependency>
<dependency>
<groupId>com.oracle.database.jdbc</groupId>
<artifactId>ojdbc8</artifactId>
<version>21.1.0.0</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<version>3.3.0</version>
<configuration>
<finalName>my-company-${project.artifactId}</finalName>
<appendAssemblyId>false</appendAssemblyId>
<outputDirectory>../build</outputDirectory>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
</plugin>
</plugins>
</build>
</project>
Thanks for any input on what I am doing wrong here / how to achieve this with Maven.
EDIT:
As requested, here an example project as ZIP-File.
https://drive.google.com/drive/folders/1ilJeTrOPgYgUTdOP0J4BQcBnPT5fls0k?usp=sharing
The parent directories ModuleGroupCustomer and ModuleGroupCommon do represent git repositories in the real scenario. The relative module path is caused, because the maven project which should be my "run config" points to maven projects in both repositories.
Maybe I am misunderstanding Maven in general? I thought of it in terms of use cases for dependency management similar to .Net nuget packages, but also as "project configuration" like ordinary NetBeans/Intellij projects.
Is it better to simply stick to the existing NetBeans projects for day to day development?

After a long and tedious process of trial and error, I have found a solution which is working for me. So I decided to share the solution online, in case someone else runs into a similar problem. Here is a link to the final zip archive containing working example projects => File CustomerRunnable_RunningAssemblyPluginStackoverflowExample.zip https://drive.google.com/drive/u/0/folders/1ilJeTrOPgYgUTdOP0J4BQcBnPT5fls0k
My error was that I misunderstood how the assembly-plugin works. The approach that I executed the plugin inside my aggregator pom (CustommerRunnable) is wrong, as this maven project only exists as parent pom.
The CustommerRunnable pom.xml references all customer plugins as modules. Those modules have not the CustommerRunnable as parent, but a different pom. Then I created a separate maven project "distribution". The pom.xml of the distribution defines all the plugins (needed customer maven modules) as dependencies. It also has the CustommerRunnable pom.xml as parent. Hence when I run the project in NetBeans, all connected modules are also build(if necessary).
It also configures the assembly plugin. The assembly plugin is attached to the maven package-phase and thus executed with it. It also uses a custom assembly descriptor, which copies all the previously defined plugins into the right folders. This is done by using dependencySets with include and exclude patterns.
See https://maven.apache.org/plugins/maven-assembly-plugin/advanced-descriptor-topics.html for details on this.
So one dependencySet copies all jar files of all plugins to a /plugin folder by using an include pattern. Then this approach is inversed to copy the jar files of all external dependencies to a /lib folder.
The descriptor also defines some extra files to copy to a particular location. exec-maven-plugin, so I can comfortably start the customer software out of NetBeans. I didn't yet manage to configure the execute plugin correctly regarding the needed classpath arguments.
Endresult looks like this:
It is also worth noting that the configurations of the "Build project", "Run project" and "Debug project" inside NetBeans need a tiny bit of modification. (Right Click Module "distribution" -> "Properties" -> point "Actions"

Related

How to add a maven project as a dependency to another one

I've just started a java project, in which I'd like to use the classes of another project.
My pom.xml looks like this so far:
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>...</groupId>
<artifactId>...</artifactId>
<version>...</version>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.7.0</version>
<configuration>
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
What would be a good way to add that other project as a dependency in mine? Should I download all of its compiled jar files and add them one by one in my pom.xml as dependencies? Or is there a better option?
I was thinking of downloading all the jars, putting them into a directory (e.g. lib) and somehow referencing that entire directory in the pom.xml, so if there's a new version of the project mine depends on, I only have to change the contents of that lib folder for the new jars, and don't have to edit the pom.xml. Is it an option? If so, how to do that?
Or most importantly, what is the proper way you suggest doing it?
If you want to use the latest version of this project, I suggest you build it yourself. Because it seems they are releasing to Sourceforge and maintaining the code actively.
Each time you want to upgrade the version, you have to get the latest source code (via git) and use mvn install command on this projects root pom.xml to install it to your local maven repo. This project is configured as multi module maven project, using install on the root pom.xml will install all the sub modules.
On your projects pom.xml you can use mvn versions:use-latest-releases to update all your dependencies to the newest version. This command will automatically upgrade dependency versions for you.
To add a project as dependency follow Marvins link.

Need Apache commons-lang3 as dependency of an Eclipse plugin built with Tycho

I'm having one of those nights...
I'm developing an Eclipse plugin using Tycho (the Maven extension), and at some point I wanted simply to use the class StringUtils from org.apache.commons. After some research, the only way that I could find is the following code in my pom.xml parent file:
<dependencies>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.3.2</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.eclipse.tycho</groupId>
<artifactId>tycho-maven-plugin</artifactId>
<version>${tycho.version}</version>
<extensions>true</extensions>
</plugin>
<plugin>
<groupId>org.eclipse.tycho</groupId>
<artifactId>target-platform-configuration</artifactId>
<version>${tycho.version}</version>
<configuration>
<pomDependencies>consider</pomDependencies>
<environments>
<environment>
...
This didn't work, and any other solution that I tried didn't work either.
I'm using Maven for the first time, so maybe I'm missing something (or a lot of things)...
Does anyone have an idea? I'd be very thankful :o)
Your configuration looks correct. So if it doesn't work, you are probably missing the dependency declaration in the MANIFEST.MF. To do this, e.g. add Require-Bundle: org.apache.commons.lang3 in that file.
Background: A dependency in the POM doesn't automatically mean for Tycho that your bundle also automatically has this dependency. It only means that the artifact will be added to the target platform (given that pomDependencies=consider is configured and the artifact is an OSGi bundle - both is true in your case). Once it is in the target platform, it can be used to resolve the dependencies declared in your bundle's MANIFEST.MF.
It sounds like you need to "upgrade" to using a target platform to define your target.
How are you achieving this dependency in your development environment? If you are not using a target platform, you are inheriting whatever plug-ins are installed in your development (that is the default target platform).
Create Target Platform
First create a target platform. I recommend using the Target Platform Definition DSL and Generator to create and edit the target platform.
The tpd file will look something like this for orbit
target "name"
with source requirements
location "http://download.eclipse.org/tools/orbit/downloads/drops/R20150519210750/repository/" mars-orbit {
org.apache.commons.lang3
}
location "http://download.eclipse.org/releases/mars" mars-release {
org.eclipse.platform.feature.group
org.eclipse.equinox.executable.feature.group
org.eclipse.e4.rcp.feature.group
org.eclipse.ui.trace
org.eclipse.pde.feature.group
}
This example uses the already created OSGi bundles for third-parties. You can choose which release of orbit and browse all the available packages on the Orbit Site. You can also use auto-completion in the tpd editor.
Tycho Using Target Platform
Place the target file in a new plug-in. Name the target file the same as the plug-in. (e.g. com.example.releng.targetplatform.target is the name of the target file in this example.)
In this project, a pom that looks like this:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>com.example.releng.targetplatform</artifactId>
<packaging>eclipse-target-definition</packaging>
<parent>
<groupId>com.example</groupId>
<artifactId>com.example.releng</artifactId>
<version>1.0.0-SNAPSHOT</version>
<relativePath>../com.example.releng</relativePath>
</parent>
</project>
You can configure (in your releng pom.xml) the target configuration like this:
<plugin>
<groupId>org.eclipse.tycho</groupId>
<artifactId>target-platform-configuration</artifactId>
<version>${tycho-version}</version>
<configuration>
<target>
<artifact>
<groupId>eGui</groupId>
<artifactId>com.example.releng.targetplatform</artifactId>
<version>1.0.0-SNAPSHOT</version>
</artifact>
</target>
</configuration>
</plugin>
Tutorial
Have a look at Code & Me's excellent tutorial on Tycho, it goes into more detail and over many steps goes from new project to a complete Tycho.

Is there a Maven plugin that runs a non-fat jar?

Imagine a normal java maven project with a Main class that produces the artifact project-a.jar. This project has a dependency on project-b.jar.
Is there a Maven plugin that allows to run that jar by a command like that?
mvn run-plugin:run org.mygroup:project-a:3.1 <args>
The plugin would resolve the runtime dependencies (using META-INF/maven/(...)/pom.xml), install the project and its dependencies to the local maven repository (if not already there), construct the classpath and invoke
java -cp (...)/project-a-3.1.jar;(...)/project-b-2.1.jar org.mygroup.Main <args>
I know that the usual way is to build an executable (fat) jar that contains the dependencies, but that's not what I am asking for.
Actually, it is not even necesary to read the pom from the jar, because maven can download it from the repositories given the coordinates.
Why this question is different to the Maven Run Project question:
I do not want to start from having the project's source already checked out. So the usual use of the exec plugin is not applicable. The OP of the Maven Run Project question obviously assumed the presence of a source code project folder. Her purpose was testing and she accepted an answer that clearly needs a project. The wording of both questions is correct, too. There is a difference between the words "project" and "jar" and their actual meaning in their respective contexts is quite different.
You can use the appassembler-maven-plugin plugin, it creates a shell script that has the dependencies in the classpath for you. Heres an example config
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>appassembler-maven-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>assemble</goal>
</goals>
</execution>
</executions>
<configuration>
<extraJvmArguments>-Xms256m -Xmx1536m</extraJvmArguments>
<programs>
<program>
<mainClass>com.package.MyMainClass</mainClass>
<name>TestFormattingUtils</name>
</program>
</programs>
</configuration>
</plugin>
You can find the output script in .../target/appassembler/bin You can manually inspect the script and you'll see that its doing the type of command you wanted where it adds the jars to classpath via the command line. ie java -jar (...)/project-a-3.1.jar -cp (...)/project-b-2.1.jar <args>
I'm not a fan of jars-in-jar either, but I do maintain various tools with lots of dependencies. So, at one point, I decided to write an executable AppBoot jar which puts all the jars from a lib-subdirectory in a class-loader and then calls the main-method of the desired (executable) jar. This question prompted me to investigate if the exec-maven-plugin could do something similar, and it can.
The exec-maven-plugin does not require a "Java project" directory, but a pom.xml in a directory is required. The pom.xml I used is shown below, note that it can be placed in any (empty) directory and the application can be started by opening a shell/prompt in that directory and executing mvn exec:exec. Use mvn -X exec:exec to review the classpath used by the exec-maven-plugin.
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.descartes</groupId>
<artifactId>exec-embed-demo</artifactId>
<version>1.2.2-SNAPSHOT</version>
<packaging>pom</packaging>
<!-- Start the demo using Maven repository artifacts, execute with "mvn exec:exec" -->
<properties>
<demo.version>1.2.1.GH</demo.version>
<mainclass>com.descartes.basicjsp.embed.demo.Launch</mainclass>
<appname>${project.artifactId}</appname>
<homedir>${project.basedir}/</homedir>
</properties>
<dependencies>
<dependency>
<!-- exec-maven-plugin will get all required (runtime) jar-files from this dependency. -->
<groupId>com.descartes</groupId>
<artifactId>basic-jsp-embed-demo</artifactId>
<version>${demo.version}</version>
</dependency>
</dependencies>
<build>
<!-- The "outputDirectory" is added to the classpath by the exec-maven-plugin. -->
<!-- Add this pom's directory to the classpath instead of "./target/classes". -->
<!-- The directory should contain "logback.xml" to prevent a million lines of debug output from Tomcat. -->
<outputDirectory>${homedir}</outputDirectory>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.4.0</version>
<!-- mvn exec:exec configuration -->
<!-- Embedded Tomcat will not stop with "ctrl-c" -->
<!-- Use http://localhost:8080/shutdown instead -->
<configuration>
<executable>java</executable>
<arguments>
<argument>-Dapp.name=${appname}</argument>
<argument>-Dapp.home.dir=${homedir}</argument>
<argument>-Dapp.conf.dir=${homedir}</argument>
<argument>-cp</argument>
<classpath/>
<argument>${mainclass}</argument>
</arguments>
</configuration>
<!-- mvn exec:java configuration -->
<!-- "ctrl-c" stops Tomcat but embedded Tomcat fails to start properly, probably a classloader issue. -->
<!--
<configuration>
<mainClass>${mainclass}</mainClass>
<systemProperties>
<systemProperty>
<key>app.name</key>
<value>${appname}</value>
</systemProperty>
<systemProperty>
<key>app.home.dir</key>
<value>${homedir}/</value>
</systemProperty>
<systemProperty>
<key>app.conf.dir</key>
<value>${homedir}/</value>
</systemProperty>
</systemProperties>
</configuration>
-->
</plugin>
</plugins>
</build>
</project>
AppBoot is part of the basic-jsp-embed project that uses embedded Tomcat and that project can be found here (to install, download the latest release, unpack the zip-file and run "mvn install" in the root directory of the multi-module project).
On a side-note: managing a jar-set is tricky, use tools like jHades to verify you will not run into trouble with multiple versions of the same class in different jar-files.
You are looking for the maven exec plugin.
mvn exec:java -Dexec.mainClass="com.example.Main" [-Dexec.args="argument1"]
would run your program
Maven can not do what you want, simply because it has no way to resolve the dependencies of project A once it has been built into a final jar.
Maven does not magically download libraries from the Internet: what makes it work are the definition of repositories inside the pom.xml. Without pom.xml, like you seem to suggest, how would it know where to download libraries from? Maven is not a downloading tool, it is a project management tool and what you have is no longer a project but a final library.
Since you have control over project A, you should really rely on Maven conventions and either build a fat jar or an assembly (with maven-assembly-plugin).
By the way, the pom.xml file located under META-INF is not guaranteed to exist, and, in fact, it is not there if you look at Spring artifacts. Take a look at Maven Archiver documentation: the presence of this pom file is controlled by the addMavenDescriptor boolean attribute. Set this attribute to false and your main artifact will not have this pom file.

Maven Modules assembly/shade build

I have the following module structure:
powercontrol
powercontrol-core
pom.xml
powercontrol-data
pom.xml
powercontrol-gui
pom.xml
powercontrol-ui
pom.xml
pom.xml
Now I want that the GUI (Graphical User Interface) and UI (Command Line User Interface) can be executed by the client.
I tried to use the maven shade plugin inside the GUI and UI, but this makes it really a mess.
I prefer:
A jar file with all the third party dependencies (log4j etc).
A jar file (or maybe lib folder?) with all the project modules.
A'n executor for the GUI and UI.
Example:
powercontrol/
bin/
gui
ui
lib/
third-party.jar
powercontrol-core.jar
powercontrol-data.jar
powercontrol-gui.jar
powercontrol-ui.jar
I'm a bit stuck with getting a good structure now, where should I start?
All feedback, suggestions etc are welcome. Thank you in advance!
UPDATE 8/28/2015
I made a new module named: powercontrol-dist that will be executed as last in the Maven lifecycle. This module will generate a lib folder and copy all the dependencies from the powercontrol-gui and powercontrol-cli to this folder.
Now I have 2 questions!
Question 1
Is this a good way to go? Or is there a better way?
powercontrol-dist/pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>nl.nberlijn.powercontrol</groupId>
<artifactId>powercontrol</artifactId>
<version>1.0</version>
</parent>
<artifactId>powercontrol-dist</artifactId>
<packaging>pom</packaging>
<name>PowerControl Dist</name>
<description>Dist</description>
<dependencies>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>powercontrol-gui</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>${project.groupId}</groupId>
<artifactId>powercontrol-cli</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-dependency-plugin</artifactId>
<version>2.10</version>
<executions>
<execution>
<id>copy</id>
<phase>package</phase>
<goals>
<goal>copy-dependencies</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/lib</outputDirectory>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
Output:
powercontrol/
bin/
gui.exe
ui.exe
lib/
third-party-lib.....jar
third-party-lib.....jar
third-party-lib.....jar
powercontrol-core.jar
powercontrol-data.jar
powercontrol-gui.jar
powercontrol-cli.jar
Question 2
Also I want to make two .exe files "gui.exe and cli.exe" referencing to the powercontrol-gui.jar and the powercontrol-cli.jar.
Is adding a mainclass to the manifest inside the pom.xml in the powercontrol-gui and powercontrol-cli module enough?
<build>
<plugins>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
<configuration>
<archive>
<manifest>
<mainClass>${main.class}</mainClass>
</manifest>
</archive>
</configuration>
</plugin>
</plugins>
</build>
If you want two executable JARs (gui.jar, ui.jar), you should add the shade plugin to those two modules, so that as part of each module, a standalone executable JAR is built. Both of the JARs will contain all the third-party stuff as well. You cannot create a standalone executable JAR where parts of the dependencies are in an external JAR (unless you do you own classloader magic or unless you also have to specify the external JAR on the command line).
If you are stuck with the maven shade plugin, you should tell us what problem exactly you have. Typically these can be resolved. A common problem is that certain files need to be "merged" when a shaded JAR is created, in particular files in META-INF e.g. used by Spring or by the Java Service Locator mechanism. The shade plugin offers support for such merging, but it needs to be configured for the case at hand.
Btw. I'd recommend calling the command line version "cli.jar" - "ui" sounds like "gui".
Ok, since you updated your question and now seem to be asking for a "native launcher" (exe file) instead of an executable JAR file - those are completely different things.
Launching an exe file from the command line:
C:\> gui
Launching an executable JAR file from the command line
C:\ java -jar gui.jar
To get the first, you need to create a native launcher that internally invokes Java. A project that might support you in that task could be launch4j - they also seem to provide a Maven plugin.

Java: How do I build standalone distributions of Maven-based projects?

I often encounter distributions of Java applications or libraries which
use Maven as their build tool.
Some of them, sadly, don't provide standalone (or redistributable) jars.
Is it possible to build Maven-based applications in such a way, that
the build result contains all dependencies and can be redistributed to work out-of-the box?
I tried to build Jackrabbit's OCM module.
For some very "intelligent" reasons there is no downloadable standalone
version.
So I built Jackrabbit with Maven (the source package of Jackrabbit includes
OCM), and got the same jar as found in the apache repository.
The jar doesn't contain necessary dependencies and is useless to me.
As Dominic said, using the assembly plugin will do the trick. You would usually configure it inside your own project's POM to gather and package all required dependencies:
...
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
</plugin>
...
jar-with-dependencies is predefined by the assembly plugin and will include all dependencies in the final package (see the documentation here).
If you don't want to use Maven for your own project, you will need to modify the libraries' POMs and repackage them yourself (download the sources, add the above snippet to pom.xml and run mvn package). Beware of duplicate or incompatible transitive dependencies if you use multiple libraries. exclusions might help in that case (see documentation here).
Use the Maven Shade plugin
...but be careful of the gotchas (similar to the one described further down my answer), which has got a workaround explained here.
Also, be ultra careful with the Shade plugin config. I accidentally used double <configuration> tags once, and the transformers didn't apply at all, and the plugin also took the liberty of not warning me.
Don't use the Maven Assembly plugin
assembly:single will unpack your dependency JARs as-is, and this could not be what you want. E.g. stuff like META-INF/spring.schemas will be overridden with the last Spring dependency JAR that's evaluated, and as such your XSDs won't be found (apart from those in the last JAR, of course). Which is why systems like Alfresco made their AMP plugin which bundles dependencies inside lib/ inside the AMP you're building. The latter raises dependency management issues, though.
You may have some luck with the appassembler plugin. Failing that, take a look at the assembly plugin. That's more flexible, but lower level. If you're using the assembly plugin, you may find the chapter on it in maven: the definitive guide to be useful.
As a couple of the posters said, the assembly plugin is a good way of creating a complete jar file, with all project dependencies. However, you don't actually have to modify the pom.xml file. Simply run:
mvn assembly:single -DdescriptorId=jar-with-dependencies
... in order to create a jar file. If you want to do anything more advanced, you should probably modify pom.xml, and create a custom assembly descriptor.
Change the pom.xml file and use the <Embed-Dependency> directive. A similar example can be found here so you can adapt it to your scenario.
<Embed-Dependency>*;scope=!test;inline=true</Embed-Dependency>
I think this should do the trick.
Here is the example at the above URL that seems to give timeout.
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>br.gov.lexml</groupId>
<artifactId>toolkit</artifactId>
<packaging>bundle</packaging>
<version>3.0</version>
<parent>
<artifactId>lexml</artifactId>
<groupId>br.gov.lexml</groupId>
<version>1.0</version>
</parent>
<build>
<finalName>Lexml_Toolkit-2.0</finalName>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.5</source>
<target>1.5</target>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.felix</groupId>
<artifactId>maven-bundle-plugin</artifactId>
<extensions>true</extensions>
<configuration>
<instructions>
<!--_include>src/toolkit/resources/META-INF/MANIFEST.MF</_include-->
<Export-Package>*;-split-package:=merge-last</Export-Package>
<Bundle-Activator>br.gov.lexml.borda.Toolkit</Bundle-Activator>
<Bundle-Name>Toolkit</Bundle-Name>
<Private-Package />
<Embed-Dependency>*;scope=!test;inline=true</Embed-Dependency>
<Bundle-ClassPath>.,{maven-dependencies}</Bundle-ClassPath>
</instructions>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.apache.xmlbeans</groupId>
<artifactId>xmlbeans</artifactId>
<version>2.4.0</version>
</dependency>
<dependency>
<groupId>org.apache.xmlbeans</groupId>
<artifactId>xmlbeans-xmlpublic</artifactId>
<version>2.4.0</version>
</dependency>
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>1.2.15</version>
</dependency>
<dependency>
<groupId>br.gov.lexmlbeans</groupId>
<artifactId>lexmlbeans</artifactId>
<version>3.0</version>
</dependency>
</dependencies>
</project>
I believe the Maven Shade Plugin will satisfy your needs. I use it when I am building command line interface tools to create an Uber JAR including my classes and along with the classes from all my dependencies.
Its very easy to use and I think this example is self-explanatory.

Categories

Resources