sialcasa / mvvmFX

an Application Framework for implementing the MVVM Pattern with JavaFX
Apache License 2.0
489 stars 104 forks source link

Support building of the library with OpenJDK 11+ #576

Open manuel-mauky opened 5 years ago

manuel-mauky commented 5 years ago

At the moment the library is still configured to be build with Java 8. While Java 8 will still be the target version in future releases, it has to be possible to build the library with newer versions.

To fix this, we have to configure maven to add openjfx dependencies when a newer java version is used.

ntherrien commented 5 years ago

Hi @lestard, I am myself in the process of updating my team's software to Java 11 and I came accross this ticket.

I was wondering why would mvvmfx need to target java 8 in the future? From my experience this is near impossible. You would be lucky if all of the project's dependencies can be built as-is in Java 11 without any hacks.

From my limited experience upgrading our software base to Java 11, it seems like the general trend in the community is to simply "move on" to Java 11. All the libraries we are using are now built against Java 11 with bytecode version 52. These newer releases are not linkeable with Java 8 apps and that is just how it is.

I've also seen some projects use a branching system to be able to offer updates to the Java 8 lineup. These projects usually have more resources too.

I just thought I'd share this with you because I think moving to Java 11 might be easier for you and this community if 1.9.0 was simply moving to Java 11 instead of trying to support both Java 8 and 11 in the same master branch. A compromise might be to build with Java 11 but release on Java 8 compatible bytecode.

Also, I would be willing to help updating the project to Java 11 if you want. I see this issue as a priority because the JavaFX community is moving to OpenJFX faster since Oracle changed the licensing on Java 8. There is no windows build for OpenJFX 8 which is why I've seen many move to OpenJFX 11 with maven support.

Regards,

Nicolas

manuel-mauky commented 5 years ago

Hi @ntherrien, thanks for your comment. The main reason is that we are using the framework in projects were migration away from Java 8 isn't that easy and won't be happening within the next 1-2 years. If we would change our build in a way that JDK 8 isn't working anymore and a then a bug pops up and needs to be fixed, we would have a problem. I don't say that I like this and if I have the opportunity I would definitely migrate but thats also "just how it is" ;-)

And a side note: Oracle provides support for JDK 8 until 2025 (see here) though it's payed support. This is what some of our customers are doing to have more time on migrating.

The wish to make building with JDK 11+ possible is mainly a developer convinience thing. As developers we like to use newer OpenJDKs and don't want to keep old versions installed.
Using newer features of the language is not a big reason at the moment.

I like to keep the code-base compatible to JDK 8. My initial idea was to somehow configure OpenJDK 11 to produce a build-result that is compatible with JDK 8 but as far as I know this isn't possible. Therefore the second idea was to have 2 separate build processes. One that uses JDK 8 and produces the actual published artifacts and one that uses OpenJDK 11 and can be used by developers to implement new features. What I also can imagine is to additionally publish artifacts that where build by OpenJDK 11. I'm ok with introducing new maven-artifact-ids for the old artifacts like 'de.saxsys:mvvmfx-jdk8' and to point the normal artifacts to the new OpenJDK 11+ builds.

A solution with separate branches maybe would also work but I assume that this makes integrating features and bugfixes harder as the code-bases would diverge.

I'm happy to get suggestions of how to improve the build but in the end the requirement is still there: I need a build artifact that is compatible with JDK 8.

A question on this: As far as I know it's still possible to use old libraries with newer JDKs. I've tested OpenJDK 11 and it was working perfectly fine with the mvvmfx library. The only problem was the missing module-names (which is fixed in the newest snapshot version). So is there any actual difficulty from the perspective of an application developer (in other words: only user of the library) when using old Jars with older bytecode versions?

ntherrien commented 5 years ago

Hi @lestard !

Understood.

Your idea of using two build pipelines might just work. From my experience so far, the impact of using Java 11 on code itself is limited to:

Other than that, Java 8 code should build just fine under Java 11, allowing two pipelines to build successfully.

However, to answer your question, there is another aspect to consider that falls outside of the build itself. Even though the code might build under Java 11 doesn't mean it runs as part of the user's application.

That is due mostly to two situations:

Second point is a concern for MVVMFX. When the user tries to run MVVMFX with OpenJFX 11 on Java 11, there's a bunch of exceptions:

java.lang.IllegalAccessError: class javafx.scene.control.Control (in unnamed module @0x385f2bdc) cannot access class com.sun.javafx.application.PlatformImpl (in module javafx.graphics) because module javafx.graphics does not export com.sun.javafx.application to unnamed module @0x385f2bdc

This is because in the OpenJFX project, all packages under com.sun.javafx.* are NOT exported as part of the useable API. The only choice the user has is to add --add-exports directives to the VM parameters. This allows the application to run, but having done it for our apps, there is a LOT of them and the command line becomes a bit ridiculous. I can provide a list if interested.

That being said, I have raised an issue against OpenJFX because I believe the export rules that they have set are limiting extensibility by other libraries such as MVVMFX. I have quoted this project as an example but I also found another issue where the user got fed up and decided to rebuild the source code without the export restrictions. https://github.com/javafxports/openjdk-jfx/issues/538

Depending on what the OpenJFX community has to say about that (it would be very easy for them to fix this, but they might have reasons against it), this might mean that any com.sun.* classes used in this repo would have to be copied and brought into this project somehow. If they choose to export those as well, this would be good news for MVVMFX and the code would run smoothly on Java11+ as well.

Another aspect to note about the future of MVVM and the decision of keeping Java 8 compatibility is that OpenJFX 11+ does NOT support Java 8. The OpenJfx community decided to go with a scheme where the version of JFX matches the version of the JVM. OpenJfx 13 is expected to work on Java 13 but not necessarily on 11. So any customer who wishes to use the latest JavaFX features are expected to update their JVM version as well. Because of that, their would have no way of using MVVMFX at this time. Perhaps this versioning convention would also make sense for MVVMFX since it so heavily depends on OpenJfx. That also solves the question of maven artifact names as the version would start with the release number it is targeting.

You are also correct about Oracle offering paid support, but that wasn't what I meant. Our company uses Azure DevOps to build our applications in the cloud. That means we are dependent on hosted agents which configuration follow the community's trends. When Oracle announced paid support, all oracle jdks were removed and replaced with OpenJDKs. As you know, OpenJDK does not include JavaFX. The JavaFX sdk can be installed separately but there is a specific case where support fell in the cracks: open javafx 8 support on windows is not available. Perhaps this is where i'm wrong and you know of a way to add javafx 8 on an agent without using the oracle jdk? I could find no maven support, no openjfx sdk for windows.

In general, I found no way to build Windows -native Java FX 8 applications for free. You must pay Oracle to use its JDK8. I could not find a way of building JavaFX 8 without infringing the new Oracle License.

The good thing with the licensing change by Oracle is that the community is now moving heavily towards OpenJDK 11+ and its free builds like the Azul series, This might just be the encouragement developers needed in order to get moving on the new JVMs.

Of course, using Azure DevOps and cloud environments is entirely "our problem", but since I love MVVMFX and see that many other companies I work with are following suit with Microsoft Azure, I would be willing to put some effort and help build a Java 11 compatible MVVMFX :) i think its well worth the effort.

ntherrien commented 5 years ago

Here's what it looks like when we try building other OpenJFX components with Java 8. In this case ControlsFX 11: [ERROR] bad class file: C:\Users\ntherrien.m2\repository\org\controlsfx\controlsfx\11.0.0\controlsfx-11.0.0.jar(org/controlsfx/dialog/ExceptionDialog.class) [ERROR] class file has wrong version 55.0, should be 52.0

manuel-mauky commented 5 years ago

Hi, well thats a lot of info. I hope I don't miss something ;-)

We aren't using 'com.sun' classes. The only reference I found in the code was an unused import in one class (and I've fixed it right away). So this shouldn't be a problem. If you've found any other usage of 'com.sun.*' classes in the repo, please tell me as this would definitely be a bug and needs to be fixed.

Are you sure that the exception you've postet is coming from mvvmFX? If I get the exception right, it tells that javafx.scene.control.Control is using an illegal class, not one of "our" classes. Another thing to keep in mind is that with version 1.8.0 we added automatic module names for all artifacts. However, we messed up some of them as "-" isn't allowed in module names. I've fixed it here but this change is only available in the snapshot versions at the moment. Could it be possible that the exception is a result of an older version of mvvmFX?

You can also see our jigsaw-example which demonstrates the usage of mvvmFX with OpenJDK 11. On my machine this example starts up without any exceptions. The goal of this example was to see what works and what does not work so if you see anything that is relevant in real-world apps regarding OpenJDK 11+ support, I'm happy to get feedback. If there is an issue with mvvmFX you can extend this example so that we can reproduce the issue.

Does the decission of the OpenJFX team to drop JDK 8 support really influences third-party libraries that keep Java 8? The example of ControlsFX is quite different isn't it? They have source code that targets Java 11 and of cause this can't be build with Java 8. But with mvvmFX it's the other way around: We are targeting Java 8 and this should be possible to build with newer JDKs. You've said it yourself "Java 8 code should build just fine under Java 11". And as long as mvvmFX doesn't use internal com.sun.* classes I don't see the issue to use it together with OpenJFX 11.

I don't know the build process of Azure but I'm totally with you that we should make building with OpenJDK possible to fix this. The customers I have in mind that are sticking with JDK 8 don't use such modern build pipelines but instead are configuring their jenkins build servers by hand. My goal is to support both approaches.

In theory it should be possible to use a newer javac to compile for an older target version. It should be possible to use OpenJDK 11 to produce classes that are compatible with Java 8. However, the last time I tried this I had troubles with module-info.java. My idea was the following:

However, when targeting java 8, javac wasn't ignoring the module-info but instead stopped compiling. This was just a prove-of-concept and I stopped working on this because I haven't found the time to proceed but maybe this could be a good starting point for another try.

ntherrien commented 5 years ago

Haha yes this is a lot of information! I think its cool that you are still very much active with MVVMFX :)

Let me try to put together an example which fails at runtime. It will make it easier to test afterwards. I'm beginning to think this might have to do with the fact that the app im building is structure in multiple jars. For example, there is a "common" jar with common dialogs in it and a "main" jar which makes use of those common dialogs.

Be right back with you.

tobiasdiez commented 5 years ago

@lestard What you describe should be possible using javac --release 8, see JEP 247: Compile for Older Platform Versions and the maven example

ntherrien commented 5 years ago

@lestard Ok so I put some effort down this morning to set up a public repo with a stripped down example showing the issue. The code is stripped down from a real life app and I tried to preserve some of its structure since it is cross-referencing resources between jars. Here is the link: https://github.com/ntherrien/mvvmfx-java11-test

In the folder called "logs and screenshots" you will find screenshots of what the app should look like and logs when building and running on java 8 and logs when building and running on java 11.

As the logs show, when on java 8, I use zulufx OpenJDK build. It is a free alternative to Oracle that I found out about yesterday. Azure Hosted Agents use Azul Zulu builds so that's how I got the tip. Under Java 8, the JavaFX runtime comes from zulufx and is at version 8 (the openjfx dependencies have no effect)

On Java 11, I use the official 11.0.2 reference build of OpenJDK which does not include OpenJFX. Under Java 11, the maven Open JFX runtimes are used.

Check under the parent pom.xml file for a section you should comment out depending on if youre building on Java 8 or Java 11.

That should provide us common ground for testing our theories on Java 11 support.

ntherrien commented 5 years ago

@lestard I've come to notice that even a simple HelloWorld program will get a similar IllegalAccessException when running outside of the scope of the jfx maven plugin. I have opened an issue on their github: https://github.com/javafxports/openjdk-jfx/issues/539

I'm letting you know because that could mean the issue could be unrelated to mvvmfx after all. Once I get a reply back from them I will test it using the project I uploaded and see if i can get past other errors I had seen which had mvvmfx classes listed in the logs.

Will be keeping you posted as soon as I get more information from the OpenJFX team.

ntherrien commented 5 years ago

I,ve added logs showing the error when trying to run using maven jfx plugin. An MVVMFX-less project runs fine with maven jfx plugin, but will not run with it.