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.