7u10: JavaFX packaging tools update
- by igor
Last weeks were very busy here in Oracle. JavaOne 2012 is next week. Come to see us there!
Meanwhile i'd like to quickly update you on recent developments in the area of packaging tools. This is an area of ongoing development for the team, and we are continuing to refine and improve both the tools and the process. Thanks to everyone who shared experiences and suggestions with us. We are listening and fixed many of reported issues. Please keep them coming as comments on the blog or (even better) file issues directly to the JIRA.
In this post i'll focus on several new packaging features added in JDK 7 update 10:
Self-Contained Applications: Select Java Runtime to bundle
Self-Contained Applications: Create Package without Java Runtime
Self-Contained Applications: Package non-JavaFX application
Option to disable proxy setup in the JavaFX launcher
Ability to specify codebase for WebStart application
Option to update existing jar file
Self-Contained Applications: Specify application icon
Self-Contained Applications: Pass parameters on the command line
All these features and number of other important bug fixes are available in the developer preview builds of JDK 7 update 10 (build 8 or later). Please give them a try and share your feedback!
Self-Contained Applications: Select Java Runtime to bundle
Packager tools in 7u6 assume current JDK (based on java.home property) is the source for embedded runtime. This is useful simplification for many scenarios but there are cases where ability to specify what to embed explicitly is handy. For example IDE may be using fixed JDK to build the project and this is
not the version you want to bundle into your application.
To make it more flexible we now allow to specify location of base JDK
explicitly. It is optional and if you do not specify it then current JDK will be used (i.e. this change is fully backward compatible).
New 'basedir' attribute was added to <fx:platform> tag. Its value
is location of JDK to be used. It is ok to point to either JRE inside
the JDK or JDK top level folder. However, it must be JDK and not JRE as we need
other JDK tools for proper packaging and it must be recent version of
JDK that is bundled with JavaFX (i.e. Java 7 update 6 or later).
Here are examples (<fx:platform> is part of <fx:deploy> task):
<fx:platform basedir="${java.home}"/>
<fx:platform basedir="c:\tools\jdk7"/>
Hint: this feature enables you to use packaging tools from JDK 7 update
10 (and benefit from bug fixes and other features described below) to create application package with bundled FCS version of JRE 7 update 6.
Self-Contained Applications: Create Package without Java Runtime
This may sound a bit puzzling at first glance. Package without embedded Java Runtime is not really self-contained and obviously will not help with:
Deployment on fresh systems. JRE need to be installed separately (and this step will require admin permissions).
Possible compatibility issues due to updates of system runtime.
However, these packages are much much smaller in size. If download size
matters and you are confident that user have recommended system JRE
installed then this may be good option to consider if you want to improve user experience for install and launch.
Technically, this is implemented as an extension of previous feature.
Pass empty string as value for 'basedir' attribute and this will be
treated as request to not bundle Java runtime, e.g.
<fx:platform basedir=""/>
Self-Contained Applications: Package non-JavaFX application
One of popular questions people ask about self-contained applications -
can i package my Java application as self-contained application? Absolutely.
This is true even for tools shipped with JDK 7 update 6. Simply follow steps for creating
package for Swing application with integrated JavaFX content and they will work even if your application does not use JavaFX. What's wrong with it? Well, there are few caveats:
bundle size is larger because JavaFX is bundled whilst it is not really needed
main application jar needs to be packaged to comply to JavaFX packaging requirements(and this may be not trivial to achieve in your existing build scripts)
javafx application launcher may not work well with startup logic of your application (for example launcher will initialize networking stack and this may void custom networking settings in your application code)
In JDK 7 update 6 <fx:deploy> was updated to accept arbitrary
executable jar as an input. Self-contained application package will be created preserving input jar as-is, i.e. no JavaFX launcher will be embedded. This does not help with first point above but resolves other two.
More formally following assertions must be
true for packaging to succeed:
application can be launched as "java -jar YourApp.jar" from the command line
mainClass attribute of <fx:application> refers to application main class
<fx:resources> lists all resources needed for the application
To give you an example lets assume we need to create a bundle for application consisting of 3 jars:
dist/javamain.jar
dist/lib/somelib.jar dist/morelibs/anotherlib.jar
where javamain.jar has manifest with Main-Class: app.Main Class-Path: lib/somelib.jar morelibs/anotherlib.jar
Here is sample ant code to package it:
<target name="package-bundle">
<taskdef resource="com/sun/javafx/tools/ant/antlib.xml"
uri="javafx:com.sun.javafx.tools.ant"
classpath="${javafx.tools.ant.jar}"/>
<fx:deploy nativeBundles="all"
width="100" height="100"
outdir="native-packages/" outfile="MyJavaApp">
<info title="Sample project" vendor="Me"
description="Test built from Java executable jar"/>
<fx:application id="myapp" version="1.0"
mainClass="app.Main" name="MyJavaApp"/>
<fx:resources>
<fx:fileset dir="dist">
<include name="javamain.jar"/>
<include name="lib/somelib.jar"/>
<include name="morelibs/anotherlib.jar"/>
</fx:fileset>
</fx:resources>
</fx:deploy>
</target>
Option to disable proxy setup in the JavaFX launcher
Since JavaFX 2.2 (part of JDK 7u6) properly packaged JavaFX applications have proxy settings initialized according to Java Runtime configuration settings.
This is handy for most of the application accessing network with one
exception. If your application explicitly sets networking
properties (e.g. socksProxyHost) then they must be set before
networking stack is initialized. Proxy detection will initialize
networking stack and therefore your custom settings will be ignored.
One way to disable proxy setup by the embedded JavaFX launcher is to pass
"-Djavafx.autoproxy.disable=true" on the command line. This
is good for troubleshooting (proxy detection may cause significant
startup time increases if network is misconfigured) but not really user friendly.
Now proxy setup will be disabled if manifest of main application jar has "JavaFX-Feature-Proxy" entry with value "None". Here is simple example of adding this entry using <fx:jar> task:
<fx:jar destfile="dist/sampleapp.jar">
<fx:application refid="myapp"/>
<fx:resources refid="myresources"/>
<fileset dir="build/classes"/>
<manifest>
<attribute name="JavaFX-Feature-Proxy" value="None"/>
</manifest>
</fx:jar>
Ability to specify codebase for WebStart application
JavaFX applications do not need to specify codebase (i.e. absolute location where application code will be deployed) for most of real world deployment scenarios. This is convenient as application does not need to be modified when it is moved from development to deployment environment.
However, some developers want to ensure copies of their application JNLP
file will redirect to master location. This is where codebase is
needed. To avoid need to edit JNLP file manually <fx:deploy> task now accepts optional codebase attribute. If
attribute is not specified packager will generate same no-codebase files
as before.
If codebase value is explicitly specified then generated JNLP files
(including JNLP
content embedded into web page) will use it. Here is an example:
<fx:deploy width="600" height="400"
outdir="Samples"
codebase="http://localhost/codebaseTest"
outfile="TestApp">
....
</fx:deploy>
Option to update existing jar file
JavaFX packaging procedures are optimized for new application that can use ant or command line javafxpackager utility. This may lead to some redundant steps when you add it to your existing build process.
One typical situation is that you might already have a build procedure that produces executable jar file with custom manifest. To properly package it as JavaFX executable jar you would need to unpack
it and then use javafxpackager or <fx:jar> to create jar again (and you need to make sure you pass all important details from your custom manifest).
We added option to pass jar file as an input to javafxpackager and <fx:jar>. This simplifies integration of JavaFX packaging tools into
existing build process as postprocessing step. By the way, we are looking for ways to simplify this further. Please share your suggestions!
On the technical side this works as follows. Both <fx:jar> and
javafxpackager will attempt to update existing jar file if this is the
only input file. Update process will add JavaFX launcher classes and update the jar manifest with JavaFX attributes. Your custom attributes will be preserved. Update could be performed in place or result may be saved to a different file.
Main-Class and Class-Path elements (if present) of manifest of input jar file will be used for JavaFX application unless they are explicitly overriden in the packaging command you use. E.g. attribute mainClass of <fx:application> (or -appclass in the javafxpackager case) overrides existing Main-Class in the jar manifest. Note that class specified in the Main-Class attribute could either extend JavaFX Application or provide static main() method.
Here are examples of updating jar file using javafxpackager:
Create new JavaFX executable jar as a copy of given jar file javafxpackager -createjar -srcdir dist -srcfiles fish_proto.jar -outdir dist -outfile fish.jar
Update existing jar file to be JavaFX executable jar and use test.Fish as main application class javafxpackager -createjar -srcdir dist -appclass test.Fish -srcfiles fish.jar -outdir dist -outfile fish.jar
And here is example of using <fx:jar> to create new JavaFX executable jar from the existing fish_proto.jar:
<fx:jar destfile="dist/fish.jar">
<fileset dir="dist">
<include name="fish_proto.jar"/>
</fileset>
</fx:jar>
Self-Contained Applications: Specify application icon
The only way to specify application icon for self-contained application using tools in JDK 7 update 6 is to use drop-in resources.
Now this bug is resolved and you can also specify icon using
<fx:icon> tag. Here is an example:
<fx:deploy ...>
<fx:info>
<fx:icon href="default.png"/>
</fx:info>
...
</fx:deploy>
Few things to keep in mind:
Only default kind of icon is applicable to self-contained applications (as of now)
Icon should follow platform specific rules for sizes and image format (e.g. .ico on Windows and .icns on Mac)
Self-Contained Applications: Pass parameters on the command line
JavaFX applications support two types of application parameters: named and unnamed (see the API for Application.Parameters).
Static named parameters can be added to the application package using
<fx:param> and unnamed parameters can be added using
<fx:argument>. They are applicable to all execution modes including standalone applications.
It is also possible to pass parameters to a JavaFX application from a Web page that hosts it, using <fx:htmlParam>. Prior to JavaFX 2.2, this was only supported for embedded applications.
Starting from JavaFX 2.2, <fx:htmlParam> is applicable to Web
Start applications also. See JavaFX
deployment guide for more details on this.
However, there was no way to pass dynamic parameters to the
self-contained application. This has been improved and now native
launchers will delegate parameters from command line to the application code. I.e. to
pass parameter to the application you simply need to run it as "myapp.exe somevalue" and then use getParameters().getUnnamed().get(0) to get "somevalue".