edvin / fxlauncher

Auto updating launcher for JavaFX Applications
Apache License 2.0
714 stars 110 forks source link

Java 9 compatibility #100

Open jmerle opened 6 years ago

jmerle commented 6 years ago

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.

mordechaim commented 6 years ago

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.

jmerle commented 6 years ago

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 commented 6 years ago

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.

mordechaim commented 6 years ago

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 notifications@github.com 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

jmerle commented 6 years ago

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.

edvin commented 6 years ago

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.

oparkerj commented 6 years ago

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

edvin commented 6 years ago

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.

ronsmits commented 6 years ago

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.

mordechaim commented 6 years ago

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?

TravFitz commented 6 years ago

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.

ronsmits commented 6 years ago

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.

TravFitz commented 6 years ago

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 commented 6 years ago

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

mordechaim commented 6 years ago

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.

edvin commented 6 years ago

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

ronsmits commented 6 years ago

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.

mordechaim commented 6 years ago

Dom parser doesn't break compatibility...

edvin commented 6 years ago

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 :)

ronsmits commented 6 years ago

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.