Monday, November 18, 2013

Native Java Packaging with NetBeans 7.4

One of the new features of NetBeans 7.4 that made the "NetBeans 74 NewAndNoteworthy" page is "Native Packaging," which is described on that page as "JavaSE projects now support creation of native bundles taking use of the native packaging technology provided by JavaFX."

I will use a very simple example to demonstrate this native packaging functionality in NetBeans 7.4. The next code listing is for this enhanced Hello World example.

EnhancedHelloWorld.java
package dustin.examples;

import static java.lang.System.out;

/**
 * Slightly enhanced "Hello World" example.
 * 
 * @author Dustin
 */
public class EnhancedHelloWorld
{
   /**
    * Main function.
    * 
    * @param args the command line arguments; name being addressed, if any.
    */
   public static void main(String[] args)
   {
      final String addresseeName = args.length > 0 ? args[0] : "World";
      out.println("Hello, " + addresseeName);
   }
}

The next image shows this same code in the NetBeans 7.4 source code editor.

To use the Native Packaging feature, I can right-click on the project and select Properties as shown in the next image.

Clicking on "Properties" leads to the appearance of the "Project Properties" window. This window, as shown in the next screen snapshot, allows the developer to expand the "Build", select "Deployment", and check the box next to the label "Enable Native Packaging Actions in Project Menu." Selecting this option configures NetBeans 7.4 to support native packaging for that NetBeans project.

With NetBeans 7.4 native packaging enabled, I can now right-click on the project and have a new option called "Package as" available. When I select that "Package as" option, I see the following choices: "All Artifacts", "All Installers", "Image Only", "EXE Installer", and "MSI Installer". Note that my NetBeans 7.4 IDE is running on a Windows machine, so the EXE and MSI installers make sense. Sections 6.4.1 and 6.4.2 of the Deploying JavaFX Applications document cover the EXE and MSI installer packages respectively.

When I select EXE as the installer package, I see it processing the native packaging per the message in the bottom right corner of the IDE. This is shown in the next screen snapshot.

The first time I tried this, I ran into an error reported by NetBeans with the message: "JavaFX native packager requires external Inno Setup 5+ tools installed and included on PATH to create EXE installer. See http://www.jrsoftware.org/". Going to the referenced Jordan Russell Software site allows me to download Inno Setup 5.5.4 (isetup-5.5.4.exe). In my case, I downloaded the self-extracting EXE and ran it. I then added the full path to the directory into which Inno Setup 5.5.4 was installed to my PATH environmental variable and restarted NetBeans 7.4.

With Inno Setup installed on my system, the Inno Setup 5.5.4 installer compiler runs when NetBeans's EXE native packaging is selected. When NetBeans and Inno Setup complete, a relatively large EXE file exists in the project's directory as shown in the next screen snapshot.

I can run this executable, of course, by simply typing its name at the command prompt. The next screen snapshot demonstrates that running this executable leads to a popup window requesting approval to install the Java application.

When the "Install" button is clicked, the installation begins and this is demonstrated in the next screen snapshot.

The executable installer installs the Java application as another executable. In this case, this application is installed in C:\Users\Dustin\AppData\Local\EnhancedHelloWorld as shown in the next screen snapshot.

The generated directory shown in the screen snapshot above includes a "runtime" directory with the necessary JRE to run this application even on machines that don't have a JRE installed. The Java application itself is stored as a JAR in the "app" directory. Both of these subdirectories are shown in the next two screen snapshots.

The generated directory includes two .exe files. One is EnhancedHelloWorld.exe, which is the Java application executable. The other .exe file is unins000.exe. Running this latter .exe file cleanly uninstalls the application from the computer.

The next screen snapshot shows that I am able to start the application from my Window Start in addition to clicking on the generated executable file.

Although the Java code sample I started with can be built as an executable application using NetBeans 7.4 as shown in this post, it is far more interesting to use a Java application with a user interface because standard output is not written anywhere visible to the user. For example, one could build an executable application with NetBeans 7.4 based on the Java class HelloWorldSwing.

My examples in this post have been entirely Java SE (no JavaFX), but have taken advantage of NetBeans 7.4's support of native packaging via mechanisms generated for JavaFX deployments. Therefore it's not surprising that the JavaFX documentation on Self-Contained Application Packaging is useful for understanding the options available. Native packaging with NetBeans 7.4 is also demonstrated in Native Packaging in NetBeans IDE.

Addendum

Based on feedback comments to this post, I have added this clarifying section.

The primary use of native packaging would be for situations where one wants to make a Java-based application available to customers who might not have an appropriate Java Runtime Environment installed on their machines. This approach "packages" the application with the necessary runtime support classes. As grelf.net points out, it is easier if all the customers already have appropriate versions of the JRE installed on their machines. In that case, the deployment might be as simple as delivering an executable JAR.

The feedback from iyoskusmana reminded me of two other points I wanted to make clearer. The example Java code I started my post with works in the sense of giving me something to build and deploy from NetBeans 7.4. The downside of that particular code, however, is that its standard output does not get written to anywhere the user of the application can see. Although it does run, there is not much evidence of that. This is why it is better to use a Swing-based GUI application such as the suggested HelloWorldSwing.

It is also important to set the class whose "main" function should be used by the natively packaged application in the Project Properties "Run" section (MainClass field). In other words, treat the native application deployment like you would an executable JAR and specify to NetBeans which of the classes in that JAR is the one whose "main" function should be executed when the application is executed.

9 comments:

iyoskusmana said...

Hi, I follow your instruction and it's working. But in the end, when I run the EnhancedHelloWorld.exe file, it has nothing print "Hello World". What's wrong?

@DustinMarx said...

iyoskusmana,

Try the same procedure on the class HelloWorldSwing as contained at http://docs.oracle.com/javase/tutorial/displayCode.html?code=http://docs.oracle.com/javase/tutorial/uiswing/examples/start/HelloWorldSwingProject/src/start/HelloWorldSwing.java.

You can use the class largely as is with the package name adjusted for the package it lives in. Make sure also to have the "Main" class for the project set to this class.

Dustin

grelf.net said...

Why would anyone want to do this? One of the virtues of Java is that it can run on so many different systems. Why then restrict your application to one system?

grelf.net said...

Why would anyone want to do this? One of the prime virtues of Java is that appliocations will run on so many different systems. So why limit your program to one system?

@DustinMarx said...

grelf.net,

That's a great question that I wish I had addressed in the original post.

The primary use of this would be for situations where one wants to make a Java-based application available to a wide variety of customers, some of who might not have an appropriate Java Runtime Environment installed on their machines. This makes approach "packages" the application with the necessary runtime support classes.

Of course, it is easier if all the customers already have current/desired JREs on their machines and then simply an executable JAR would be sufficient.

Dustin

Sean Phillips said...

grelf.net,

Agreed with @DustinMarx. What you'll find in the real world is that nobody has the same JRE installed and many have no JRE installed because of insane incorrect FUD about "Security!!"

The Native Packager support also mitigates the argument from HTML5 fanboys that "Java Sucks because you have to download a JRE". (even though their apps barely works after you download and install an entire browser)

Fred Janon said...

Interesting NetBeans feature, thanks. I do encounter situations from time to time where I wish I had that solution. Much easier than asking the client to install Java first.

iyoskusmana said...

@DustinMarx

This is work. Thanks for sharing. :)

Jasper said...

I love this feature, but I wish I could change the icon of the package before it gets built. Do you know how to do this?