Showing posts with label javafx. Show all posts
Showing posts with label javafx. Show all posts

Friday, March 10, 2023

Deploying LogoRRR to Apple's App Store using JPackage


From the outset of this project, I had a strong desire to deploy
LogoRRR to the App Store. Despite my best efforts, I was unable to achieve this goal last year. However, with the release of version 23.2.0, I reached my goal and put LogoRRR into the store. In hindsight, the process was easier than I anticipated.

Initially, I tried to call the necessary tools directly to create the pkg, and used jlink to create temporary app images, but this proved unnecessary. Instead, I used jpackage, which was able to assemble everything I needed in its latest release. I encourage you to use my findings as a starting point for delivering your application to a global audience.

Here's a quick outline of my approach:

  • I used JavaFX as the GUI technology and Scala as the implementation language.
  • Maven was used as the build tool.
  • JPackage was used to create a pkg suitable for deployment to the App Store
  • Source code is available at github

To dive a little deeper into the deployment using JPackage:

  • I circumvented the modular JavaFX approach by using my own Launcher class.
  • I put everything application-related in a shaded jar.
  • I created a libs directory for everything else.
  • I created the necessary Entitlements and plist files for JPackage.
  • To keep things clean, I used an 'options' file for JPackage.

To verify my package, I used Apple's Transporter App, which gave me a quick response on any missing files in my package.

One key technique to get a valid plist file was to create a stub project in XCode to investigate the syntax required for a successful deployment.

In conclusion, deploying your application to the App Store using JPackage is a viable option. With careful attention to the steps outlined above, you too can achieve success in reaching a global audience.

Sunday, October 2, 2022

A JavaFX Fanboy forgets about his Parallels subscription - what happens next?

Recently, I was informed by a friendly message on my phone that the yearly subscription fee for Parallels - THE best way to run windows on your mac - was already sucked away from my bank account. 



I rarely use it, in fact I didn’t start it on my M1 Mac ever. 


Well, screw it! I recently brushed up LogoRRR's UI and was curious how the changes would look like on windows. 


As such I went to the Parallels website, and in no time I had setup their product fresh on my computer. First thing I was informed was that I could throw away my old Windows Image which I transferred from my old macbook. The architectures wouldn't match, I was out of luck.


Great. Well as said before I didn’t really miss it too much and decided to proceed. Install everything from scratch.  How to get a new Windows? Very conveniently, I just clicked “next”. 


There you go, in no time I had a brand new Windows for aarch64 running on my virtual PC! Thanks to my internet connection and I could solve my first world problems in no time here.


My quest continued. 


Only after having installed IntelliJ and a proper JDK on this virtual machine and after a clone of LogoRRR resided on my virtual HD I realised that there was no build for Windows and aarch64 for JavaFX base libraries available. 






I was already suspicious after not having a choice to download a JDKFx from Azul? I was seeing the wall approaching very fast. 


But being on fire I checked out the openjfx source code as well, and tried to compile it. 🤷🏼‍♂️ 


I followed OpenJFX's build instructions - For example I downloaded Visual Studio. Which is available for Windows aarch64 in an early preview. Of course I realised this only after being informed by the 'normal' Visual studio installer that this platform I'm running on was not supported. 


I smiled along the way, no way this would work - but I continued.


After installing cygwin as well I was sure jfx wouldn’t compile, since this was only a x86 version for it.


Anyway, I continued, and after ignoring all warnings and instructions on the openjfx wiki to install a certain gradle version I just went with the most current one.


Finally, I got to execute gradle with the default task ‘sdk’. 


It promptly aborted with a message ‘platform not supported’. 


There you have it!


Well, I just searched the whole jfx source for this message, found it and short circuited the if statement which aborted the build.





To my suprise this was the only thing which was necessary for a successful build! I got all the jars and modules!?? 


Well ... ok!


But! I need maven artefacts to fire up LogoRRR - how go get those? The official docs state there existed some publish tasks for maven, but I couldn’t find it.


Being on fire I searched the source code again, and I was lucky again! There exists a property to activate those publish tasks, and I bravely activated them.




Having no idea what I was doing, but needing javafx modules graphics, control, swing and base in my local maven repository, I went on. I even defined my own version number for openjfx.


Now I changed the version for JavaFX in my LogoRRR’s code, changed the openjfx version and the module path in the run configuration and gave it a go.


After a peculiar long compilation time, finally LogoRRR showed up. 🥳


LogoRRR Screenshot


Lessons learned

I’m not really sure that I got a clean aarch64 build for openjfx on windows, more likely a mixture of an emulation and aarch64 bits of the build. Otherwise this would have been too easy. 


At least LogoRRR started up and worked like it was supposed to do. Which it didn’t prior to my quest. The trigger here was the message 'javafx platform not supported' in IntelliJ. 


… The broader message is that open source can work for you in many ways, for everybody on his level.


Programming has to do with a certain attitude. Often one reads of ‘fearless refactoring’. What should I be afraid of? No laptop exploded so far (I know of) because somebody renamed a variable ...


I also realised that openjfx is just a project like any other project - you can download it, inspect it, tinker with it ... you could even contribute to it in some or the other way - for example like i did with the answer on stackoverflow - all contributions are valuable, even if it is not always technically correct or imperfect.



Sunday, September 11, 2022

ZIO and JavaFX - Hello World

As part of learning ZIO (http://www.zio.dev/)  for other projects I’m working on I’ve decided to use LogoRRR as a testbed to see which challenges have to be solved in the context of JavaFX application programming with Maven and Scala.

For context:

ZIO is a framework to perform type-safe, composable asynchronous and concurrent programming for Scala.  

LogoRRR is a desktop application written in Scala, leveraging JavaFX as desktop application technology. LogoRRR helps to analyse log files and its target audience are support/devops engineers.


Starting fresh with no relevant ZIO experience, I’m interested in the CI setup. LogoRRR uses maven as build system, which is rather uncommon for a Scala project. There are two reasons for that - I know maven quite well, and I’m using Gluon’s  gluonfx-maven-plugin - that's the main reason why I'm using maven here. 


Anyway, now I’m confronted with following challenges:

  • How to setup a maven project with ZIO?
    • Is ZIO compatible with LogoRRR’s GraalVM compilation workflow?
  • How to integrate ZIO with JavaFX?

Monday, October 26, 2020

A native Scala JavaFX application via GraalVM

After successful attempts with Java, JavaFX and GraalVM I get closer to my goal to compile SudokuFX to a native binary. A milestone towards this goal is to compile a trivial Scala JavaFX application to native code, that is to say to a single, dependency free binary. Source code and binaries for windows and MacOsX for this blog post are available here.

03 - Sydney Harbour Bridge Construction
 Sydney Harbour Bridge Construction

JavaFX Logboard

As a vehicle for using JavaFX and FXML I chose to implement a simple log visualisation tool. I'll call it javafx-logboard. It is a JavaFX application which displays green, red, yellow and gray rectangles in a FlowPane, symbolizing INFO, SEVERE, WARNING and TRACE messages. It is nothing fancy, but helps identifying swiftly if there are problems or certain patterns in an application log. With this visualisation, it is easier to detect patterns. Try it! Honestly, I'm wondering why common log viewers don't have such a 'birds eye' feature. 

A screenshot will make things clearer: 

The application helps to get a quick idea about what is going on in a log file. It even sports Tooltips for red rectangles (SEVERE entries) and Drag'n Drop. I always wanted to have such a tool, well I wrote it in 10 minutes (*). It reminds me visually a little of XCopy, an ancestor of XCode (nerd joke). 

Motivation

I started this project and blog post with following promise:

If javafx-logboard compiles to a native binary, I'll be a true believer in GraalVM and will AOT compile my way through various applications in the future. (at least try it)

Side-note: I already successfully compiled an application with JavaCV for MacOsX with GraalVM, this dependency involves more native code I'll ever want to write in my life. But Seeing a Scala JavaFX app running with my own eyes, that should be the the mission for this blog post. 

The motivation for having a native binary is primarily an easier way for distributing software in my mind, in regard of speed and memory consumption it may help twitter but is not really relevant for me ... or is it? 

I believe GraalVM produces more efficient Scala runtime code, it would be great to experience a perceptible difference for my own applications as well.  There is no other way, you have to try it out. 

Some takeaways after spending far too much time on this endeavour until everything worked


Scala Converters

I have experienced some errors with GraalVM compilation which I traced back to scala.jdk.CollectionConverters, but I think it has something to do with implicit resolution of Scala methods. I'm not quite sure what is the issue with it, my solution was to use Java Collections just to get it to run. I'm sure GraalVM has no problem consuming Scala Collections via some extra configuration maybe (will have to solve / tackle this again in future projects anyway ... )

FXML References 

It took some time until I realised that classes won't get automatically included via GraalVM if you use UI elements in FXML without referencing them in your Controller. You have to explicitly add them in your reflection list, otherwise they get lost and you'll get weird runtime behaviour. Or reference them in your controllers. 

fat-jar

Antother thing I've learned is that you don't need to modularise your Java/Scala application in order to compile it with GraalVM. Just provide a shaded jar and there you go.

main-class not found with scala javafx apps?

I experienced something rather intriguing - if I tried to call GraalVM via maven client plugin in the same project like I compiled my Scala sources, I always would get an error - GraalVM compilation would not find the entry point to the appilation, it's main class (which was written in Scala).

Not thinking long about it, I created a multi module maven project which contains all relevant Scala source code, and one with a minimalistic Java main class which can be found by the maven client plugin. I don't know if I did something wrong here (again), it seems rather odd. But with a small Java bootstrapper it works fine.

multimodule maven project - mvn install

Since I use a trick to compile my Scala stuff to a shaded jar to trick client-maven-plugin to compile it as 'normal' byte code I have to use mvn install - otherwise it would not find the dependency (for example with mvn package). In my opinion this should not make any difference, but at the moment it does. Somebody an idea what's going on here?

long compile times - again

This multi-module approach is more or less inevitable anyways since compile times for GraalVM are long. For application development it is not really feasible to wait so long for testing features and such. 

As such it is good practice to make sure your application runs on a VM (in a shaded fat jar for example) and only then try to compile it to native code. Beware: The added complexity for application developers not only to implement a feature but also keep control of the whole build chain doesn't really simplify application development. This is a huge problem in my opinion, and a hurdle for adoption. :( 

Remember however that a little waiting and listening to the noise of the fan yields finally an AOT compiled binary, everything included, no JRE download, all in one package. Which is just mind-blowing and well worth the effort!

scala-native - the other way 

Speaking of which - I want to mention Scala Native here as well, which is a project to compile Scala directly (via LLVM) to native code. With a tighter integration in the Scala compiler more specific optimisations are possible and hence faster, smaller binaries (compared to GraalVM) are possible. ... In theory. It is a shame that this project doesn't get as much attention, love and money it would need to reach a more mature state and really compete with GraalVM. For example, I doubt it would be able to compile JavaFX apps at the moment. 

file sizes acceptable

Back to GraalVM: It is also interesting how big a Scala JavaFX application can be at minimum without any magic - at about 65 MB for MacOsX, which is not much larger than a Helloworld JavaFX (FXML) application directly from gluon samples project. 

I tried my little toy project this time also with windows, and after following instructions from here it compiled without much hassle literally on the first try. Binary size on windows is roughly the same, at about 60 MB. 

Depending on your background or internet access speed those sizes are negligible or a major drama, decide for yourself. If you are keen on minimal file sizes, you should stop by at pouet.net and ask yourself if you have made the right choices as a programmer in your life. 

low hanging fruits

In retrospect it turns out that configuring native compilation with Maven, JavaFX client plugin, GraalVM and Scala is easier than it may sound. It heavily depends on a proper configuration of the toolchain, and this has to be learned. Since this whole process includes compiling your code with GraalVM, I should mention that normal compilation is said to be faster with GraalVM as well (for Scala code). Another reason to consider using it (just as compile vehicle, without creating native images).

For the time being, I'm happy with my GraalVM experiments and try to migrate codebases as soon as I can to be consumable by client-maven-plugin. Some of those journeys I may document here in the future. 

Source code and binaries for windows and MacOsX for this blog post are available here.

(*) implementing Drag'n Drop took me 10 minutes, but debugging why it would not work the way I expected took hours. It had to do with GraalVM very aggressively stripping away JavaFX containers and no log output was given. Drag'n drop works fine, you just have to be cautious about making sure that everything is really contained in your exe file - afterwards it is always easy ;-)




Saturday, October 17, 2020

javacv-webcam: GraalVM edition

TLDR: java-webcam can be compiled with GraalVM to a native binary, source code available here. 

Preparing the slipway for a launch
Tyne & Wear Archives & Museums


Recently, I managed to find some time to get a custom java runtime image to work with JavaCV and a simple webcam application, which opens nice possibilities to play around doing image processing with Java.

On the other hand, if you have followed the Java community lately, you've been surely pointed several times to the current big thing Panama and Loom, ah I mean of course GraalVM

I'm very fond of the vision of GraalVM, which tries to provide a common platform for several different language eco systems (among other things), in my view a meta supplier for many business opportunities, not clear at the moment what the implications are really. 

It goes without saying that it would be great to get JavaCV and JavaFX to run with GraalVM as well.

Disclaimer: I'm just an interested developer who applies mentioned technologies, more or less successfully.  I cannot stress enough how grateful one can be for enabler technologies like JavaFX, JavaCV or GraalVM. 

Ok. What is necessary for a webcam binary, written in Java, at the time of writing? 

The good news is: not much. In retrospect (after hours - I still can't believe it works now, at least at the moment, for me, in my small bubble).

After much fiddling around the only thing really necessary was bringing together the right tools. I'm using GraalVM 2020.2.0 and Maven 3.6.2 at the moment, the most recent XCode, brew ... well ok ... probably much libraries and toolchains I'm not aware of (neither I want to be - to be honest). 

But the good news is that apart from setting up your environment "properly" and checking out javacv-webcam 2020.3.1,  all you have to do is to enter following command:

mvn clean client:build client:run -Djavacpp.platform.custom -Djavacpp.platform.host -Dgraalvm.home=/path/to/graalvm

After downloading all dependencies (can take some time!) and compiling (forget about download times, this is the real deal), you'll get a huge binary AND a running webcam application (most probably after having been asked to grant permissions by your friendly OS). ... which made my day!

Alternatively, you can start javacv-webcam binary then like this:

target/client/x86_64-darwin/net.ladstatt.javacv.javacv-webcam

Currently, this binary is huge (>500MB!), which is a little too much for my taste ;-) - a simple Hello World without JavaCV has around 60 MB (try compiling HelloFX in gluon-samples project). 

In this regard I'm sure it is possible to reduce the size by applying a more specific configuration. The best - only - chance I see here is to tinker around with JavaCV's dependencies, be more explicit with exclusions, hope that still everything you need works. To be honest, I already had to exclude one transitive dependency, otherwise linking didn't work with GraalVM. 

I just had luck my example app didn't need this specific library I guess. 

Anyway, the road for an easier deployment of Java image processing applications is paved, which is simply exciting! Slap like now!

Monday, October 12, 2020

javacv-webcam: a skeleton project to do image processing with java

Recently I've simplified JavaCV Webcam project for an easy start with JavaCV and JavaFX.

If you follow me on this blog or my occasional posts on twitter, you surely know that I like to explore new features for JavaFX in combination with Scala. Lately, I had migrated SudokuFX to JavaCV. With this release SudokuFX doesn't use OpenCV directly anymore but uses JavaCV's wrapper which provided at the point of writing a more low level API to the Mat data structure. 

SudokuFX provides some examples on how to use JavaCV, however if you search for a simple example on how to use JavaCV and JavaFX and you want to access your webcam, javacv-webcam is the right project for you. 

javacv-webcam is written in 100% Java. It shows how to configure javafx-maven-plugin to create a custom java runtime image with jlink. 

Another aspect which is worth mentioning is that javacv-webcam is an example for a modular java application. Here it is worth mentioning that IntelliJ in a recent version has good support for writing module-info.java and compiler errors are helpful as well. 

I tried to make javacv-webcam a project with zero configuration, you should just be able to check out the project and just run it ... 

Note: on windows or linux you have to apply small changes in module-info.java, but this should pose no problem. On MacOsX you may have to fiddle around with privacy / security settings for java. Speaking of which - you have to use Java11 and a recent maven distribution.

For build instructions, just checkout github readme page. This post refers to javacv-webcam version 2020.3.0.

Note: There is an older version for javacv-webcam which is implemented in Scala and does some comparisons to other ways how to use JavaCV. Also, there is a newer version for javacv-webcam which contains configuration to compile it to a native binary using GraalVM.
















Monday, August 17, 2020

SudokuFX Version 2020.3.0

After successfully prototyping a webcam image stream with latest JavaFX goodies my next step for my hobby project SudokuFX is clear - port everything to JavaCV and use it's implementation to speedup SudokuFX.


With version 2020.3.0, I rewrote almost everything; conceptually my application follows the original approach, but the implementation is simpler and yields itself better for future enhancements.


Some highlights:

- SudokuFX uses JavaCV
- got rid of overcomplicated usage of Scala Future's
- improved image recognition by tweaking used templates
- improved visual appearance by a smarter approach to overlaying empty cells with numbers, not replacing them
- better memory and CPU utilisation
- Changed versioning scheme to use revision / changelist
- Upgrade to JavaFX 15-ea+4
- Upgrade to Scala 2.13.3
- many other small improvements and bug fixes ... 

There is one drawback - currently there is no android support anymore in the current version, but I'm trying to reactivate it again (maybe more, but you know how it works for hobby software side projects ... )

I'll describe some of the mentioned points above now in more detail ...

SudokuFX uses JavaCV now ... why?


Let me start with basic project setup, that is to say maven dependencies and stuff you need to get SudokuFX to work. 

Speaking of maven dependencies, this is the major reason why I'm switching from 'pure' OpenCV to JavaCV, since it is somehow - magically - fully mavenized and I can use OpenCV indirectly in my application by using JavaCV APIs. 

No need to compile OpenCV myself, no fiddling around with CMake, just staying in my cozy maven Java dependency world, which should lower the bar to start with this project substantially.

Of course JavaCV imposes certain new rules and approaches for the programmer, you have to adapt a little bit and make yourself acquainted with another API. For this project however it payed off. 

I discovered some spots to improve the image processing. It runs way faster and more reliable now.

On the other hand, one has to be careful not to run in subtle bugs which arise from off heap memory management which is a fancy way to say that you'll get exposed to native code behaviour. 

Anyway, starting point for the rewrite to JavaCV was to use raw data from Mat via ByteBuffers, which I only found in JavaCV's API, not in OpenCV. Maybe I'm right, there is no equivalent for this in pure OpenCV C++ / Java API, maybe someone points me to it. With my current approach I'm quite happy, 2020.3 release runs way faster than any other version of SudokuFX so far :)

No more Scala Futures

Scala has a Future implementation in it's standard lib, but it doesn't have the best reputation. All discussions in the Scala community lately made me rethink my approach, and in the end I realized that this pervasive usage of Scala's Future in my code didn't really speed up things, but only bloated the whole source and made it less understandable. As such I refactored this construct out of the source, with planning to later reintroduce it again after cleaning up structure. But I learned that my problem didn't really profit from Future's, as such they are left out completely at the current state of affairs. I can imagine that I'll reintroduce some parallelism again, but at the moment the algorithm runs faster than before. Maybe I'll come back to it and optimise it more, I don't know.

Improved image processing by adapting templates

I'm using template matching for recognising numbers, no third party library like tesseract for example. This keeps it simple, but is certainly a weak point in the approach. Here the project could profit by using a simple neural net maybe. By tweaking and disambiguating the used templates however SudokuFX is now capable of recognising quite a lot of different fonts, which is great (some fonts however will fail miserably ;-) )

Improved visual appearance


One thing I'm quite fond of is that SudokuFX now overlays the computed solution with the original image, yielding a much better visual appearance of the solved Sudoku. It looks far more advanced than before, which is great. 

Improved resource handling

CPU as well as memory footprint are now far better than they used to be. This was also one of the goals of the refactoring, SudokuFX uses less energy, memory and utilizes CPU far better than before.

Versioning Scheme


A blog post from Axel Fontaine made me curious as to not use maven release plugin anymore, but an approach far simpler - SudokuFX is using this approach now too.

JavaFX 15-ea+4 / Scala 2.13.3


Like I reported in a recent blogpost, I migrated SudokuFX to Java11, which is a LTS version of Java and one of the first releases which where JavaFX was decoupled. JavaFX now lives it's own life - but accidentally - or rather planned - has the same release cycles like Java. 

BUT in my usecase scenario I directly profit from the fact that I can use a 'newer' JavaFX with the Java11 LTS version.

Why? Because at the moment of writing this lines here, I have troubles getting Scala to work with Java13, whereas with Java11 my project runs out of the box. 

Scala 2.13.3 is serving as a good starting point to finally change to Scala3, which will also be an interesting endeavour in the future.

So, to sum up, try it out yourself, use SudokuFX to solve your Sudoku problems, have a look at the code to learn something about Scala or JavaCV or report bugs you'll easily find and participate at github.

Monday, May 11, 2020

Webcam Image Stream with JavaCV

JavaCV?

JavaCV is a very cool library which empowers Java users to access native libraries like OpenCV or FFmpeg and many others.

Among other things, it prepackages OpenCV with maven, as such you can jumpstart in OpenCV development in mere minutes. Even if it downloads the internet without special tuning, it is as far as I know the simplest and fastest way to try out computer vision algorithms on the Java platform.

As a bonus, it enables also writing applications for Android, not to mention the usual desktop platforms like Windows / Mac and Linux.

In the past I've created some applications using OpenCV and it's official Java API, which is also available via JavaCV as far as I know. But JavaCV additionally provides API's which give you an added value as it makes using OpenCV APIs more idiomatic for a Java user, which is always a good thing for adoption.

In short, you save some time setting up your system if you just decide to use JavaCV.

Motivation

The motivation for devoting some time to JavaCV was to see if I could take advantage of the new PixelBuffer API which can use since JavaFX13 native arrays directly.

It seems clear that this should boost performance considerably and improves framerates for applications like my SudokuFX project. I've created a proof of concept  which compares different ways of using a webcam image stream based on the OpenCV stack.

In this project there are three implementations given:
  • a swing based, officially endorsed way to show a webcam / image
  • the classic JavaFX variant
  • the DirectBuffer approach
I've measured how fast each approach is, and like expected, on my machine it turns out that the last one using JavaFX with DirectBuffer is the fastest way to show a webcam image stream.

Here is the output for running the three different versions, with the swing approach being the slowest one.

home:target lad$ java -jar javacv-webcam-2020.2-SNAPSHOT-jar-with-dependencies.jar 
Mean: 719434
Mean: 628738
Mean: 601112
Mean: 579823
Mean: 565205
Mean: 552922

home:target lad$ java -jar javacv-webcam-2020.2-SNAPSHOT-jar-with-dependencies.jar classic
Mean: 9508516
Mean: 9461551
Mean: 9423204
Mean: 9419029
Mean: 9415144

home:target lad$ java -jar javacv-webcam-2020.2-SNAPSHOT-jar-with-dependencies.jar swing  
Mean: 35786482
Mean: 35410293
Mean: 35220229
Mean: 35092391
Mean: 35030641

Above numbers say that DirectBuffer approach is the way to go, no discussion about that! I didn't measure CPU load or memory behaviour, but I'm sure those numbers are better as well.

Conclusion

If you are using OpenCV and JavaFX, you should definitely give JavaCV and its enhanced API's for OpenCV a try.

Check out the source code for this blog post on github.

I would like to thank Samuel Audet who does a great job maintaining JavaCV and who also helped me get my webcam image to fit to JavaFX's PixelBuffer.

Version 2020.3.0 of javacv-webcam uses the same techniques, but is implemented in 100% Java. Check it out. 

Sunday, April 26, 2020

SudokuFX: Migration to Java11 LTS

Better late than never: now I want to migrate SudokuFX to Java11.

Up to version 2020.1.1,  SudokuFX needs a Java Runtime with JavaFX integrated - version 8. Choosing the correct Java version is the first hurdle for the casual internet visitor, very easy to 'do wrong'. Cryptic errors will drive away newcomers, will cost even pro's some time until they realize that the wrong platform is used.

Java != Java

Choosing the wrong Java version is a common problem for beginners, I must admit that it becomes more and more complicated.

Every half year a new Java version is released, with new features, and several organisations provide builds. This is a good thing, the industry has to evolve the platform, and it is good if there exist different sources for Java binaries. Many years of development went into a build process which is now simple enough for the average Bob D. Eveloper to build OpenJDK themselves, which is - considering the details - a huge accomplishment. 

For the rest of us, the question is which version of Java to choose? Oracle is still the place to go if you have much money to buy their licenses and subscriptions. Alternatives can be used from AdoptOpenJDK, Azul and others. To ease the migration costs, LTS versions are maintained for a longer period of time - Java version 11 is the one the industry migrates to at this very moment. 

And even me with my SudokuFX project.

Still one has to keep in mind that everybody is advertising their latest release, as such often the newest runtimes and jdks are downloaded, and projects written for older incarnations of those technologies maybe just don't work. 

If your project has dependencies on libraries which are also only written for a specific version of the JDK the game becomes even more complex. Then, as a Scala User, you have even more troubles since libraries for a specific version of Scala doesn't really work together with a different Scala version ... 

I didn't even mention the modularization effort of the JDK itself, which - only very slowly but in a foundational manner - reinvents the whole ecosystem yet again. 

Don't get me wrong, everything happens because of a perfectly sound reason, but it is not trivial to get everything working, considering all those moving targets. There are also not many engineers around who can really cope with those topics to be honest.

Well. Enough motivation to do the move to Java11, without any JavaFX backed in the java runtime. 

SDK! Man!

To easily switch between Java versions (and jvm based applications like sbt, lein, scala and others) a tool called sdkman exists, which is very handy and lets you download and change used version of Java with a simple command. It's like a package manager, just for specific (java) applications. Highly recommended!

Here is an example of how it looks if you want to change a java version from current one to to the version AdoptOpenJDK provided, Java version 11:

homemac:sudokufx lad$ sdk list java
================================================================================
Available Java Versions
================================================================================
 Vendor        | Use | Version      | Dist    | Status     | Identifier
--------------------------------------------------------------------------------
 AdoptOpenJDK  |     | 14.0.1.j9    | adpt    |            | 14.0.1.j9-adpt      
               |     | 14.0.1.hs    | adpt    |            | 14.0.1.hs-adpt      
               |     | 14.0.0.j9    | adpt    | local only | 14.0.0.j9-adpt      
               |     | 13.0.2.j9    | adpt    |            | 13.0.2.j9-adpt      
               |     | 13.0.2.hs    | adpt    |            | 13.0.2.hs-adpt      
               |     | 13.0.1.hs    | adpt    | local only | 13.0.1.hs-adpt      
               |     | 12.0.2.j9    | adpt    |            | 12.0.2.j9-adpt      
               |     | 12.0.2.hs    | adpt    |            | 12.0.2.hs-adpt      
               |     | 11.0.7.j9    | adpt    |            | 11.0.7.j9-adpt      
               |     | 11.0.7.hs    | adpt    | installed  | 11.0.7.hs-adpt      
               |     | 8.0.252.j9   | adpt    |            | 8.0.252.j9-adpt     
               |     | 8.0.252.hs   | adpt    |            | 8.0.252.hs-adpt     
 Amazon        |     | 11.0.7       | amzn    |            | 11.0.7-amzn         
               |     | 8.0.252      | amzn    |            | 8.0.252-amzn        
               |     | 8.0.202      | amzn    |            | 8.0.202-amzn        
 Azul Zulu     |     | 14.0.1       | zulu    |            | 14.0.1-zulu         
               |     | 13.0.3       | zulu    |            | 13.0.3-zulu         
               |     | 13.0.3.fx    | zulu    |            | 13.0.3.fx-zulu      
               |     | 12.0.2       | zulu    |            | 12.0.2-zulu         
               |     | 11.0.7       | zulu    |            | 11.0.7-zulu         
               |     | 11.0.7.fx    | zulu    |            | 11.0.7.fx-zulu      
               |     | 11.0.5       | zulu    | local only | 11.0.5-zulu         
               |     | 10.0.2       | zulu    |            | 10.0.2-zulu         
               |     | 9.0.7        | zulu    |            | 9.0.7-zulu          
               |     | 8.0.252      | zulu    |            | 8.0.252-zulu        
               |     | 8.0.252.fx   | zulu    |            | 8.0.252.fx-zulu     
               |     | 8.0.232.fx   | zulu    |            | 8.0.232.fx-zulu     
               |     | 8.0.202      | zulu    |            | 8.0.202-zulu        
               |     | 7.0.262      | zulu    |            | 7.0.262-zulu        
               |     | 7.0.181      | zulu    |            | 7.0.181-zulu        
 BellSoft      |     | 14.0.1.fx    | librca  |            | 14.0.1.fx-librca    
               |     | 14.0.1       | librca  |            | 14.0.1-librca       
               |     | 13.0.2.fx    | librca  |            | 13.0.2.fx-librca    
               |     | 13.0.2       | librca  |            | 13.0.2-librca       
               |     | 12.0.2       | librca  |            | 12.0.2-librca       
               |     | 11.0.7.fx    | librca  |            | 11.0.7.fx-librca    
               |     | 11.0.7       | librca  |            | 11.0.7-librca       
               |     | 8.0.252.fx   | librca  |            | 8.0.252.fx-librca   
               |     | 8.0.252      | librca  |            | 8.0.252-librca      
 GraalVM       |     | 20.0.0.r11   | grl     | installed  | 20.0.0.r11-grl      
               |     | 20.0.0.r8    | grl     |            | 20.0.0.r8-grl       
               |     | 19.3.1.r11   | grl     |            | 19.3.1.r11-grl      
               |     | 19.3.1.r8    | grl     |            | 19.3.1.r8-grl       
               |     | 19.3.0.r11   | grl     |            | 19.3.0.r11-grl      
               |     | 19.3.0.r8    | grl     |            | 19.3.0.r8-grl       
               |     | 19.3.0.2.r11 | grl     |            | 19.3.0.2.r11-grl    
               |     | 19.3.0.2.r8  | grl     |            | 19.3.0.2.r8-grl     
               |     | 19.2.1       | grl     | installed  | 19.2.1-grl          
               |     | 19.1.1       | grl     |            | 19.1.1-grl          
               |     | 19.0.2       | grl     |            | 19.0.2-grl          
               |     | 1.0.0        | grl     |            | 1.0.0-rc-16-grl     
 Java.net      |     | 15.ea.20     | open    |            | 15.ea.20-open       
               |     | 14.0.1       | open    |            | 14.0.1-open         
               |     | 13.0.2       | open    |            | 13.0.2-open         
               |     | 12.0.2       | open    |            | 12.0.2-open         
               |     | 11.0.2       | open    |            | 11.0.2-open         
               |     | 10.0.2       | open    |            | 10.0.2-open         
               |     | 9.0.4        | open    |            | 9.0.4-open          
 SAP           |     | 14.0.1       | sapmchn |            | 14.0.1-sapmchn      
               |     | 13.0.2       | sapmchn |            | 13.0.2-sapmchn      
               |     | 12.0.2       | sapmchn |            | 12.0.2-sapmchn      
               |     | 11.0.7       | sapmchn |            | 11.0.7-sapmchn      
 Unclassified  | >>> | 8.0.201      | none    | local only | 8.0.201-oracle      
================================================================================
Use the Identifier for installation:

    $ sdk install java 11.0.3.hs-adpt
================================================================================
homemac:sudokufx lad$  sdk use java 11.0.7.hs-adpt

Now this shell is configured to use Java11. Neat, isn't it? (You also get a taste of how many different variations of Java distributions exist, and the list is surely not complete ... )

I choose AdoptOpenJDK without JavaFX packaging, since I installed and experimented with it already some time ago. 

homemac:sudokufx lad$ java -version
openjdk version "11.0.7" 2020-04-14
OpenJDK Runtime Environment AdoptOpenJDK (build 11.0.7+10)
OpenJDK 64-Bit Server VM AdoptOpenJDK (build 11.0.7+10, mixed mode)

In IntelliJ I have to change the used JDK as well of course.

Nice. But what does it need to change for Java11 LTS support?

Here is an enforcer plugin rule to make sure we run at least at Java11 and with a certain maven version:


            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-enforcer-plugin</artifactId>
                <version>3.0.0-M3</version>
                <executions>
                    <execution>
                        <id>enforce-jdk</id>
                        <goals>
                            <goal>enforce</goal>
                        </goals>
                        <configuration>
                            <rules>
                                <requireMavenVersion>
                                    <version>3.6.2</version>
                                </requireMavenVersion>
                                <requireJavaVersion>
                                    <version>11</version>
                                </requireJavaVersion>
                            </rules>
                        </configuration>
                    </execution>
                </executions>
            </plugin>



This rules out already some problems and support tickets which is nice. 

Like mentioned above, I most certainly have to change some dependencies in my poms (my hobby).

A valuable resource for JavaFX is of course openjfx.io. Here you will find simple tutorials to get you up to speed with simple JavaFX projects which you can then use for your apps. They've developed a maven plugin which does almost everything you ever want concerning JavaFX, I hope I have time to look at this in more detail soon.

The company behind this is Gluon, the most active contributor to JavaFX. They work very hard to provide a Java based platform for user interfaces on Desktop, embedded and mobile, which is very valuable for the Java community.

Thanks to them - and others - JavaFX can be used as a 'normal' maven dependency in your project. Which is awesome, from a library developer point of view as well as a user who wants to use it in their next project. 

As such, JavaFX got ripped out from the core JRE, like other elements of the JDK it got modularized in Project Jigsaw. If you want to know more about this go buy this book, thank me later.

We are getting closer to what I actually had to change in SudokuFX - namely introducing new dependencies and throwing out old unsupported ones.



            <dependency>
                <groupId>org.openjfx</groupId>
                <artifactId>javafx-base</artifactId>
                <version>11.0.2</version>
            </dependency>
            <dependency>
                <groupId>org.openjfx</groupId>
                <artifactId>javafx-swing</artifactId>
                <version>11.0.2</version>
            </dependency>
            <dependency>
                <groupId>org.openjfx</groupId>
                <artifactId>javafx-fxml</artifactId>
                <version>11.0.2</version>
            </dependency>
            <dependency>
                <groupId>org.openjfx</groupId>
                <artifactId>javafx-controls</artifactId>
                <version>11.0.2</version>
            </dependency>


In my case, I struggled a little bit with the javafx-swing dependency, since it was not obvious (at the time) it had to be included as well. As you can see I use four javafx maven dependencies.

Along the way I had to get rid of jfxtras and jfxtras-labs, which don't provide builds for Java11, at least I found none. I also got problems with the scala compiler plugins and IntelliJ (I introduced them in my last post), but I need them only occasionally and as such I commented them out again.

So to sum it up, the migration was quite painless, you can have a look at the result on github - version 2020.2 of SudokuFX ....

Thanks again for reading