How to create an exe for a java program using maven?
Usually a software is distributed as an executable file. Therefore as programmers we would need to create an .exe file for our programs. Through this post I will present you how to achieve it easily with Maven (a build automation tool used primarily for Java projects) .
A windows executable can be created by using a combination of two maven plug-ins , Maven Shade plugin and launch4j plugin.
Here is my program. It is to read an .xml file and write its content to the standard out put. In order to read the .xml file we have to use a library. Here I have used jdom2. Like that in developing software we have to depend on many libraries in order to prevent reinventing the wheel. If we are building our projects using maven we can include those dependencies in the pom.xml file .
importorg.jdom2.Document;importorg.jdom2.Element;importorg.jdom2.JDOMException;importorg.jdom2.input.SAXBuilder;importjava.io.File;importjava.io.IOException;importjava.util.List;publicclassEnvisionpublicstaticvoidmain(String[] args) File xmlFile =new File("D:\\example.xml"); SAXBuilder builder =new SAXBuilder();try Document document =(Document) builder.build(xmlFile); Element rootNode = document.getRootElement(); List books = rootNode.getChildren("book"); System.out.println("This is my book store");for(int l =0; l books.size(); l++) Element book =(Element) books.get(l); System.out.println("Name :"+book.getChildText("name")+" Author :"+book.getChildText("author")); System.out.println("----------------------------------------------------------------------");>>catch(IOException io) System.out.println(io.getMessage());>catch(JDOMException jdomex) System.out.println(jdomex.getMessage());>>>
Here is my pom.xml file. Here Maven Shade plugin is used to add all the dependencies in the program into the runnable jar file. The launch4j creates the .exe with vender information and a nice icon too.
Create Windows Executable (.exe) for Java Application
Launch4j is a cross-platform tool for wrapping Java applications distributed as jars in lightweight Windows native executable files. In this post, we will learn making such an executable file for a demo java application.
Step1 ) Create a java application
I am creating a very basic java class which simply displays a frame and some text on it. It also has the main() method which will start the application.
package com.howtodoinjava; import java.awt.Color; import java.awt.Font; import java.awt.Frame; import java.awt.Label; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; import javax.swing.JDialog; public class ApplicationMain extends JDialog < private static final long serialVersionUID = 1L; public ApplicationMain() < //Create a frame Frame f = new Frame(); f.setSize(500, 300); //Prepare font Font font = new Font( "SansSerif", Font.PLAIN, 22 ); //Write something Label label = new Label("Launch4j Maven Demo with HowToDoInJava.com"); label.setForeground(Color.RED); label.setFont(font); f.add(label); //Make visible f.setVisible(true); f.addWindowListener(new WindowAdapter() < public void windowClosing(WindowEvent e) < System.exit(0); >>); > public static void main(final String[] args) < new ApplicationMain(); >>
Step 2) Create maven file with launch4j configured in it
I have created a pom file for packaging the application as .exe file. If you feel something unclear, drop a comment.
Double-click to run is one of the easiest ways to open a program.
If the person you are sharing code with already has the right version of Java installed, they can double-click on a jar file to run it. You wrote it once, they can run it there.
If they don’t have Java installed, then there are ways to create a runnable installer like jpackage, but now they have to click through an installer to be able to run your code.
You can use Native Image to turn your code into an exe which won’t require them to have anything installed, but now you have to abide by the closed world assumption and that’s not always easy or possible.
So this post is going to focus on a fairly oonga boonga approach that will work for any app, regardless of what dependencies you include or JVM features you make use of.
The code along with an example GitHub workflow can be found in this repo and final executables can be found here.
Prerequisites
Java 9+
java --versionjlink --version
Maven
NodeJS
Step 1. Compile and Package your code into a jar.
This toy program will create a basic window that has some text that you can toggle between being capitalized.
Where the «shade» plugin will handle including the code from all of your dependencies into the jar. In this case, the only external dependency is org.apache.commons/commons-text .
Then for the purposes of this guide we will move that jar into a new directory where it will be separate from whatever other files are in target/ .
mkdir buildmv target/javaexe-1.0.jar build
Step 2. Create a Java Runtime Environment
In order to run the jar from the previous step, we will need to bundle it with a Java Runtime Environment. To do this we will use jlink .
Since the Java ecosystem hasn’t embraced modules, you most likely haven’t heard of or used jlink .
The short pitch is that it can create «custom runtime images.» Say you are making a web server. You don’t need AWT or Swing, so including all the code for that is a tad wasteful. With jlink you can make a JRE that doesn’t include the java.desktop module at all.
This system works best if your application and all of its dependencies include compiled module-info.java files which let jlink know exactly what modules you want to include. You can also manually figure out the list of required modules by using jdeps and a bit of detective work.
Even without a modular project though, we can still use jlink to effectively clone our Java installation to a directory.
Including every module gives confidence that libraries like org.apache.commons/commons-text will work as intended, even though we never figured out what modules they actually require.
Step 3. Bundle the Jar and the JRE into an executable
So with a jar containing our code and all of its dependencies in one hand and a JRE in the other, all that’s left is to stitch the two together.
The general technique for that is to
Zip up the directory containing the JRE and your application jar.
Attach a stub script to the top of that zip file which will extract the zip to a temporary directory and run the code.
There is a JavaScript library which does this called caxa. Its purpose is making NodeJS projects into executables, so it will also bundle whatever NodeJS installation is on the system. That step can luckily be skipped by passing the —no-include-node flag, so it will work just fine for this.
This will create an executable called » application .» If you are doing this for Windows you should specify » application.exe .» When the executable is run the > s in the command will be substituted for to the temporary directory where the zip file was expanded.
I am aware of jdeploy — and it does handle stuff that I didn’t cover or would be relatively hard with this scheme like code signing or automatic updates — but as far as I can tell it still requires that users run an installer.
On code signing, there is an open issue with caxa to figure out how to do that. I can make another post or update this one if an approach is figured out. I don’t quite understand the issue, so I don’t feel qualified to comment.
If any mildly ambitious reader wants to try their hand at making caxa in a different language so this process isn’t dependent on the JS ecosystem I encourage it.