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

Thursday, April 23, 2020

ScalaFix SudokuFX

I released a new version of SudokuFX, this time a maintenance release. I some warnings I got from compiling.

To make this a little bit more interesting, I used scalafix and autofix. What are those things?

Scalafix is a compiler plugin on top of Scalameta which helps rewriting source code. It provides a framework which can be used for creating own code rewriting rules as well. Autofix is an example for that - it encodes migration rules specifically for ScalaTest.

After a little bit of maven pom fiddling, autofix is configured for my project. All I needed to do was to add a compiler plugin and an additional plugin in my pluginsection of my root pom.xml:


        <pluginManagement>
            <plugins>
                <plugin>
                    <groupId>net.alchim31.maven</groupId>
                    <artifactId>scala-maven-plugin</artifactId>
                    <version>4.3.1</version>
                    <executions>
                        <execution>
                            <goals>
                                <goal>compile</goal>
                                <goal>testCompile</goal>
                            </goals>
                        </execution>
                    </executions>
                    <configuration>
                        <scalaVersion>${scala.major.version}</scalaVersion>
                        <args>
                        ...
                        </args>
                        <compilerPlugins>
                            <compilerPlugin>
                                <groupId>org.scalameta</groupId>
                                <artifactId>semanticdb-scalac_${scala.full.version}</artifactId>
                                <version>4.3.9</version>
                            </compilerPlugin>
                        </compilerPlugins>
                    </configuration>
                </plugin>
                <plugin>
                    <groupId>io.github.evis</groupId>
                    <artifactId>scalafix-maven-plugin</artifactId>
                    <version>0.1.2_0.9.5</version>
                    <dependencies>
                        <dependency>
                            <groupId>org.scalatest</groupId>
                            <artifactId>autofix_2.12</artifactId>
                            <version>3.1.0.0</version>
                        </dependency>
                    </dependencies>
                </plugin>
            </plugins>
        </pluginManagement>

Thats it ... more or less.

What is still missing is a configuration for scalafix, which is placed in a file called .scalafix.conf. (Note the '.' at the beginning of the file name). This file should be placed next to the main pom file.

Here is the file how I configured it:

rules = [
  RemoveUnused,RewriteDeprecatedNames,ProcedureSyntax,NoValInForComprehension,LeakingImplicitClassVal,NoAutoTupling
]

The inverted rule name is an autofix rule, which comes with the additional dependency for scalafix-maven-plugin. 

After configuring this, you have to call maven like that:

mvn clean compile test-compile scalafix:scalafix

After that, have a look at your git status, you'll see that many files have changed, and the plugin did what was promised: it rewrote source code, applied trivial but useful transformations. For example, it can remove unused imports out of the box, or rewrite code written in procedural style and many other things.

Scalafix can be extended with own plugins, that means in theory you could implement your own rules, specific to your needs. This enables then automatic rewrites which are not only syntactic (which could also be achieved by clever scripting) but semantic: rewrite rules know about the structure of the code. This helps for automating tasks which otherwise would bind valuable developer time ...

I removed other warnings as well, albeit manually, from the source. By doing that, I got new 'unused imports', which swiftly went away by calling just beforementioned mvn command again while I gazed with amazement to my editor watching the computer doing the work for me.

Here is a list of available scalafix rules - or at least the closest to such a list I could find.


Hope I raised your interest in this amazing tooling, check out how to configure ScalaFix for maven (and try to solve some Sudokus and let me know if it worked ;-))

Sunday, April 19, 2020

SudokuFx revisited

This blog post covers my lazy sunday afternoon where I tried to get my ancient Sudoku project running again.

screen capture of application
(If you wonder why those numbers dance around - depending on what the application recognises different solutions are calculated and presented ... yes it's not perfect ;-) )

Years ago I played around with the idea of solving Sudokus with an algorithm and used JavaFX and OpenCV to do it. Quite an unusual combination, then as it is now - but it wasn't really a bad experience at all. In my view the Java OpenCV API is quite usable, and as such I wanted to prove at least for me that I could get it to run (albeit its far from perfect ;-))

I remember spending hours playing around with different filters and effects, always proud of new things I discovered.

Today, I decided to breathe life again into this project, let's see which problems I'll encounter.

First, getting source code from github still works, my last commit already 4 years ago, zero contributors along all those years, that's what a normal OSS project looks like ;-).

I try to revive it again, just the desktop version of it, leaving the android version on my todo list.

First obstacle I hit is to compile it, OpenCV is missing on my system. OpenCV doesn't have a proper maven integration, there is an ancient issue about this, nobody had the mood or skills to solve it yet. 

Update: I learned that there is somekind of maven integration in the meantime! Great!! Anyway, I build OpenCV from scratch for this article, maybe I'll have a go at the maven build another time.

Step 1 - download and compile OpenCV 4.3.0


First, I want to mention that there are several package mangers which provide prebuilt binaries for OpenCV, homebrew for example. It may well be that this is an option you prefer If you stumbled on this page by googling (seems to be rather unlikely but well).

Ok, in the meantime they reached version 4.3.0 something, I download the zip from here but I'm too dumb to find build instructions ...  No obvious links are neither on the main page nor documentation. (They surely exist but I just didn't see them apparently)

Finally, I found them.


There are numerous steps to follow, you'll need Cmake and quite some time during compilation, educated guesses what to choose, we'll go with defaults for the first try. Unzip it somewhere, I choose

~/custom-builds/opencv-4.3.0/src/ 

since we have the famous 'out of source' build CMake proposes as best practice. This means that there is a dedicated directory for build artifacts.

As such I choose following setup:

~/custom-builds/opencv-3.4.0/src/<actual contents of zip>
~/custom-builds/opencv-3.4.0/target/<here build artefacts will be placed>

I jump to this target directory and execute there following command:

cmake ../src/

... then CMake does it's job, checks for all available goodies found on my system, I pray that the right ones I need are contained, otherwise I will have to configure it and fight the dragons of OpenCV ... again.

... But it seems that I'm lucky, at the end of the cmake output it says something about java bindings, which I'm interested in, as such it should compile it like I want.

What I personally don't want is that it installs itself to some system directory, which will definitely pollute my system and break some stuff already fine tuned there, as such I have to Issue CMake again with a proper parameter:

cmake ../src -DCMAKE_INSTALL_PREFIX=../out

(Pro tip: delete your target directory beforehand completely, thank me later). This would put OpenCv then to a directory:

~/custom-builds/opencv-3.4.0/out/

Like that I can delete it again without any trace.

I'm quite sure I don't need 98% what is going to be compiled, and some magic incantation of CMake or it's configuration would prevent compiling and linking it, but I don't want to go down that road, not today.

After configuring CMake you have to invoke 'make' as well, and do it with full throttle, meaning with some concurrent threads to speed things up (yes, you can get your coffee break since it will take a while).

That said, still being in the target directory, now execute

make -j8

which will use 8 threads to compile OpenCV (takes 5min+ on my machine)

In the meantime, I want to mention it is a huge accomplishment that building from scratch 'just works' for many environments, be it MacOsX, Windows, Linux ... this is much work and should be praised!

Everytime I compile something I'm amazed if it works first time without much hassle.... I've spent already countless hours on resolving build problems, it is a major time drain.

Anyhow, make succeeded, and all build outputs are already somewhere lying in the target dir. But with

make install

everything important for the runtime will be put to the ../out directory.

Specifically, one can find dylibs in the out/lib and out/share/java/opencv4 directory.

Step 2 - Make OpenCV available to Maven


I tried to make this easy, all you have to do is to edit the main pom file and tweak some properties and point to your opencv installation directories. Here is an example configuration:


    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <scala.major.version>2.12</scala.major.version>
        <scala.full.version>${scala.major.version}.10</scala.full.version>
        <opencv.major.version>4.3</opencv.major.version>
        <opencv.full.version>${opencv.major.version}.0</opencv.full.version>
        <opencv.install.path>/Users/lad/custom-builds/opencv-4.3.0/out/</opencv.install.path>
        <opencv.java.jar>${opencv.install.path}share/java/opencv4/opencv-430.jar</opencv.java.jar>
    </properties>

After you've changed those settings to your liking, enter following command:

mvn initialize -Pinstall-opencv -N 

Now you should be ready to go, build the project with

mvn package

It shouldn't take too long, and everything should be set up correctly. OpenCV has many dylibs / dlls, which are referenced in this project, but via maven property filtering and some pseudo magic everything should just work.

You can fire it up via (being in the main directory of the project)

java -jar sudoku-javafx/target/sudoku-javafx-2020.1-SNAPSHOT-jar-with-dependencies.jar

A JavaFx Gui should appear, on the first invocation you maybe have to tell your Os that it is ok to give SudokuFx access to the webcam.

I've blogged about this project in several other blogposts, maybe you want to read them as well.

This post is referencing code state from the 2020.1 resurrection release.

To sum up, compiling OpenCV turned out to be much easier now as it was years ago, only my code was a little bitrotten - still is - but at least it should be easier to get it to run now than it was before this little article.

Thanks for reading!