fxlauncher icon indicating copy to clipboard operation
fxlauncher copied to clipboard

Java 9 compatibility

Open jmerle opened this issue 7 years ago • 20 comments

fxlauncher does not seem to work with Java 9, due to javax.xml.bind.JAXB being a Java EE API and not being on the classpath anymore in Java 9 (related StackOverflow question).

Error:

Exception in thread "FXLauncher-Thread" java.lang.NoClassDefFoundError: javax/xml/bind/JAXB
        at fxlauncher.AbstractLauncher.syncManifest(AbstractLauncher.java:201)
        at fxlauncher.AbstractLauncher.updateManifest(AbstractLauncher.java:92)
        at fxlauncher.Launcher.lambda$start$0(Launcher.java:137)
        at java.base/java.lang.Thread.run(Unknown Source)
Caused by: java.lang.ClassNotFoundException: javax.xml.bind.JAXB
        at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(Unknown Source)
        at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(Unknown Source)
        at java.base/java.lang.ClassLoader.loadClass(Unknown Source)
        ... 4 more

Steps to reproduce:

  1. Download the demo launcher jar from the demo website.
  2. Download a Java 9 binary (I used JRE 9.0.4)
  3. Run java -jar fxlauncher.jar, where java is the binary you just downloaded, and fxlauncher.jar is the path to the actual launcher file.

The answers on the StackOverflow post suggest to add JAXB as a dependency, but I have no idea how to test fxlauncher on it's own, so I don't know if that works.

jmerle avatar Feb 21 '18 22:02 jmerle

I've designed i complete new framework which was highly influenced by this project. It is fully Java 9 compatible. In fact you must use Java 9 to use it.

You can find it here.

mordechaim avatar Mar 11 '18 23:03 mordechaim

While it sounds like a cool project, I am not able to switch to a new framework due to all current users using the launcher created by FXLauncher. While I can re-distribute a newer launcher for the people who want to use Java 9 without problems, I can't swap in your alternative because that would break the current launcher. Besides that, I don't want to force users onto Java 9.

There is a Java 9 fix for FXLauncher in #103, but it isn't merged yet.

jmerle avatar Mar 11 '18 23:03 jmerle

That might be true, I haven't tested it myself, but the issue still stands. I rather have Java 9 support for FXLauncher (even if it would take a little longer) than ask all my users to re-install using a new launcher.

jmerle avatar Mar 12 '18 01:03 jmerle

I don't see how having some users (with Java 8) use fxlauncher and your newer users with my project should make any problems or conflicts.

Also, how do you expect to update fxlauncher to your existing users? The launcher itself -- by design -- is not updatable.

You could still host your files on the same location. You could even host them on Google Drive or Dropbox with my project.

In any event, it's your choice.

On 3/11/18, Jasper van Merle [email protected] wrote:

That might be true, I haven't tested it myself, but the issue still stands. I rather have Java 9 support for FXLauncher (even if it would take a little longer) than ask all my users to re-install using a new launcher.

-- You are receiving this because you commented. Reply to this email directly or view it on GitHub: https://github.com/edvin/fxlauncher/issues/100#issuecomment-372166236

mordechaim avatar Mar 12 '18 01:03 mordechaim

If FXLauncher would support Java 9, I can distribute a new version of the launcher and tell people "Hey, if you want to use Java 9, use this launcher, but if you're fine with Java 8, just keep rocking the current one!". This would be possible because the way of distributing new releases wouldn't change, so auto-updating from the old launcher would still work perfectly fine, as long as the code I write doesn't rely on Java 9.

If I were to swap in your alternative, I could do two things:

  1. Tell everyone to re-install using the new launcher and use Java 9.
  2. Tell everyone to install the new launcher if they want to use Java 9, and deploy using both FXLauncher and your alternative to prevent the current launcher from breaking.

And again, I am not very familiar with Java 9, so what I'm claiming here might not be true, but this is how I think about it at the moment.

jmerle avatar Mar 12 '18 01:03 jmerle

Hey guys, sorry about the late reply. I'm extremely busy these days, and will be for a few more weeks. I haven't looked at the PR in detail yet, and it seems it might need some adaptation. I think we also need to keep supporting Java 8 for quite some time.

edvin avatar Mar 12 '18 06:03 edvin

I also need this change. My project is still in development though so it's not a big deal yet.

oparkerj avatar May 03 '18 20:05 oparkerj

With the recent announcement that JavaFX will be removed from the JDK, we will not be targeting JDK9, but rather the decoupled JavaFX library once it becomes available.

edvin avatar May 03 '18 22:05 edvin

fxlauncher is able to launch more then just javafx applications allthough it was intentionally meant for that. it seems that jaxb will always stay a seperate jar and the json JEP did not make it for java 9.

I propose we make a version that uses a standard property file to initialize fxlauncher and up the major version number.

ronsmits avatar Oct 09 '18 05:10 ronsmits

A properties file looks correct since there isn't any structural data in the manifest. Everything is just children of the same root node.

Oh, I missed the fact that there are multiple attributes to the 'lib' element, for instance. How can this be flattened?

mordechaim avatar Oct 09 '18 05:10 mordechaim

The decoupled JavaFX has already been released, Oracle has said that they are going to lean on OpenJFX and help support building that product. Oracle JavaFX should redirect you to the OpenJFX page.

If you add the dependencies in your pom like so to fix the JAXB issue:

<dependency>
        <groupId>javax.xml.bind</groupId>
   	<artifactId>jaxb-api</artifactId>
    	<version>2.4.0-b180830.0359</version>
</dependency>
	<dependency>
        <groupId>org.glassfish.jaxb</groupId>
        <artifactId>jaxb-runtime</artifactId>
        <version>2.3.0</version>
   </dependency>

These are both compatible with Java 9/10 and will get you running with JAXB however you will need to package them into the build so that when running the fxlauncher on another computer that it will run fine.

Another issue that I faced was with the internal API that was parsing arguments from the pom to the manifest, to alleviate that I also added a dependency for Jcommander and then I created an Args.java and parsed them through Jcommander.

The last issue I faced was the runAndWait that was from an impl (which of course we lost access to with JDK 9) so to fix that I used this function, which effectively does the same thing.

public static void runAndWait(Runnable action) {
        if (action == null) {
            throw new NullPointerException("action");
        }

        // run synchronously on JavaFX thread
        if (Platform.isFxApplicationThread()) {
            action.run();
            return;
        }

        // queue on JavaFX thread and wait for completion
        final CountDownLatch doneLatch = new CountDownLatch(1);
        Platform.runLater(() -> {
            try {
                action.run();
            } finally {
                doneLatch.countDown();
            }
        });

        try {
            doneLatch.await();
        } catch (InterruptedException e) {
            // ignore exception
        }
    }

As I mentioned in my post the other day I am happy to show you if you are interested, it does work with JDK 9/10 (and theoretically with 11) you may need to tweak a few things to make it a little more generic but they are only minor.

TravFitz avatar Oct 09 '18 05:10 TravFitz

A list in a properties file is usually stored as a comma seperated string. The advantage of using a property file over a packaged jaxb implementation is that in the case of a javafx application the javafx jar will be downloaded as a normal dependency. With a jaxb implentation you would have to make a fat (shaded) jar that IMHO defeats the purpose of fxlauncher.

ronsmits avatar Oct 09 '18 05:10 ronsmits

I am still using a property file, the Args.java only defines the names that it is searching for in the properties file like this:

package fxlauncher;

import com.beust.jcommander.Parameter;
import java.util.ArrayList;
import java.util.List;

public class Args {
    
    public ArrayList<String> includeExtensions = new ArrayList<>();
    
    @Parameter
    public List<String> parameters = new ArrayList<>();
    
    @Parameter(names = {"--cache-dir","cache-dir"}, description = "Local Source file to save updated files to")
    public String cacheDir;
    
    @Parameter(names = {"--accept-downgrade","accept-downgrade"}, description = "Allow older versions to be downloaded if cached file is newer than server")
    public Boolean acceptDowngrade = false;
    
    @Parameter(names = {"--stop-on-update-errors","stop-on-update-errors"}, description = "Stop the update process if an error is encountered")
    public Boolean stopOnUpdateErrors = true;
    
    @Parameter(names = {"--whats-new","whats-new"}, description = "Used to describe what is new in the updated version")
    public String whatsNew;
    
    @Parameter(names = {"--preload-native-libraries","preload-native-libraries"}, description = "preloaded native libraries")
    public String preloadNativeLibraries;
    
    @Parameter(names = {"--lingering-update-screen","lingering-update-screen"}, description = "lingering update screen")
    public Boolean lingeringUpdateScreen = true;
    
    @Parameter(names = {"--include-extensions"}, description = "All inclusion of files to search and add to update")
    public String includeExtensionsString;
    
    @Parameter(names = {"--parameters"}, description = "Any additional parameters that need to be passed to the launched application")
    public String parameter;
    
    @Parameter(names = {"--update-text"}, description = "The text that is wishing to be displayed on update")
    public String updateText;
    
    @Parameter(names = {"--update-label-style"}, description = "The update-text style to be applied")
    public String updateLabelStyle;
    
    @Parameter(names = {"--wrapper-style"}, description = "Application wrapper style")
    public String wrapperStyle;
}

TravFitz avatar Oct 09 '18 05:10 TravFitz

my fully compiled jxlauncher.jar including all dependencies is 42kb

TravFitz avatar Oct 09 '18 05:10 TravFitz

I may be biased, but check out how I solved the JAXB issue in myself here. I made I micro-implementation using the w3c DOM parser.

It works since we know exactly what elements we have, and I don't work with a generic XML file.

mordechaim avatar Oct 09 '18 13:10 mordechaim

That's a neat trick, but for 2.0 I think JSON would make more sense :)

edvin avatar Oct 10 '18 07:10 edvin

However I dont know if json will be part of the standard JDK as it did not make it for jdk9. We could do an intermediate jdk9 release with either the dom3 parser or a property file (property file is less code IMHO) and then if json has made it into the jdk (10?) we can switch to that

As the days are getting shorter and colder, I will start spending more time again at the keyboard.

ronsmits avatar Oct 10 '18 22:10 ronsmits

Dom parser doesn't break compatibility...

mordechaim avatar Oct 10 '18 22:10 mordechaim

JSON support can be included in a couple of small classes. 2.0 will require your users to download a new installer anyways, so backwards compatibility for the manifest is not important :)

edvin avatar Oct 11 '18 05:10 edvin

I have not been able to find a defiinitive stattement that jep 198 has made it or will make it into jdk 11. I dont know if other people have more information.

ronsmits avatar Oct 12 '18 06:10 ronsmits