fn-fx / fn-fx

A Functional API around JavaFX / OpenJFX.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Doesn't seem to work with Ubuntu out of the box

kxygk opened this issue · comments

Bug Report

Steps to Reproduce:

On Ubuntu Cuttlefish (18.10)
Install leiningen from the repository
Install openjdk-8-jre from the repository
Try to run a fn-fx project and it will not find JavaFX

Expected Result:

Installing leiningen installs openjdk-8-jre-headless. But after installing openjdk-8-jre it should include JavaFX as I understand it.

Actual Result:

What I get instead is a crash:

Exception in thread "main" java.lang.NoClassDefFoundError: javafx/scene/Group, compiling:(asparapiss/svg2jfx.clj:16:3)
	at clojure.lang.Compiler.analyzeSeq(Compiler.java:6875)
	at clojure.lang.Compiler.analyze(Compiler.java:6669)
	at clojure.lang.Compiler.analyzeSeq(Compiler.java:6856)
	at clojure.lang.Compiler.analyze(Compiler.java:6669)
	at clojure.lang.Compiler.analyze(Compiler.java:6625)
	at clojure.lang.Compiler$BodyExpr$Parser.parse(Compiler.java:6001)
	at clojure.lang.Compiler$FnMethod.parse(Compiler.java:5380)
[etc]

Additional Context:

I've also tried to install the openjfx package (which I think is for Java 11) as well as the openjdk-8-jdk

So I'm not sure if this is a bug or I'm missing something obvious here (like some additional package). I've had this project running before on a Debian system (using version 0.4.0), but unfortunately I don't remember how I set up then (but I remember it not being straightforward). I've lost that setup and had to switch to an Ubuntu system. When trying to get this old project running I ran into this crash. My project.clj has a

              [fn-fx/fn-fx-javafx "0.5.0-SNAPSHOT"]

I tried the old halgari 0.4.0 as well and have the same issue
And my namespace starts with a

If you point me to another fn-fx project to test I can do that as well

Couple of random thoughts:

  1. You may have to do more than just installing openjdk-8-jre in order to make sure you're using it rather than openjdk-8-jre-headless. Some systems (e.g. macOS) offer built-in tools for selecting which of several installed JREs to use, and there are cross platform solutions (e.g. Jabba, SDKMAN!, jenv) as well. Sadly I don't know how to confirm which JRE version is in use on Linux.
  2. Even then, I'm not 100% sure if OpenJDK (of any version) bundles JavaFX anyway - that's originally why OpenJFX was developed, as I understand it. But you should be seeing a warning from leiningen ((Warning: profile :openjfx1.8 not found.)) rather than an error, since the build script should (in theory) be attempting to select an :openjfx1.8 profile (which doesn't currently exist in project.clj).

If you have to target JRE v8 (rather than the latest LTS version - v11) it may be simplest to install the Oracle JRE v8, since that's already tested and known to work (including on Linux, since that's what the TravisCI tests use).

If using an Oracle JRE is a non-starter, it would be great if you could open up a REPL using the JRE you've already installed, and reporting the output of these commands:

(clojure.reflect/resolve-class (.getContextClassLoader (Thread/currentThread)) 'javafx.application.Platform)
; I expect this to return nil

(System/getProperty "java.specification.version")
; I expect this to return "1.8"

That way I can add that missing :openjfx1.8 profile to project.clj, add OpenJDK v1.8 to the TravisCI test matrix and we can continue troubleshooting from there.

It looks like supporting OpenJFX v1.8 may be greatly complicated by the apparent lack of published OpenJFX v1.8 artifacts in Maven Central. 😞

I made an empty project and ran

clojure-template.core=> (clojure.reflect/resolve-class (.getContextClassLoader (Thread/currentThread)) 'javafx.application.Platform)

ClassNotFoundException clojure.reflect  java.net.URLClassLoader.findClass (URLClassLoader.java:382)

clojure-template.core=> (System/getProperty "java.specification.version")
"1.8"

What do you suggest is the easiest way forward? I'm not married to any version of Java honestly. I just tried to do what was easiest and requires the least amount of messing around with my system :) and I guess when I installed leiningen from the repository it just took Java 8 as a dependency. On the leiningen website it even says:

Leiningen and Clojure require Java. OpenJDK version 8 is recommended at this time.

Is this a "soft" recommendation? Can I just uninstall Java 8/leiningen, install openjdk-11-jre and openjfx from the Ubuntu repository and then manually install leiningen by running the script from the leiningen website? Does that work?

That ClassNotFoundException exception is a bit weird - clojure.reflect has been part of core Clojure since Clojure v1.3, so I don't know why it wouldn't be found. Also, you don't need an empty project to start a REPL with Leiningen - you can run lein repl anywhere you like (i.e. outside a project directory) and it'll start up a vanilla REPL just fine. In fact I often run a REPL that way so that if my project has messed up dependencies my REPL won't be impacted.

I can't speak to Leiningen's & Clojure's JRE recommendations, but what I can say is that fn-fx is currently tested on both Oracle JDK 8 and OpenJDK 11, so picking either of those JREs is going to be the easiest path forward. You won't need to install OpenJFX at all - the project pulls that down as a library dependency when needed (i.e. on OpenJDK 11 only - it's bundled with Oracle JDK 8).

Okay.. yikes. So I uninstalled everything and installed JRE 11

geokon@ux305-ubuntu:~/bin$ apt list --installed |grep openjdk

WARNING: apt does not have a stable CLI interface. Use with caution in scripts.

openjdk-11-jdk-headless/cosmic-updates,cosmic-security,now 11.0.1+13-2ubuntu1 amd64 [installed,automatic]
openjdk-11-jdk/cosmic-updates,cosmic-security,now 11.0.1+13-2ubuntu1 amd64 [installed]
openjdk-11-jre-headless/cosmic-updates,cosmic-security,now 11.0.1+13-2ubuntu1 amd64 [installed,automatic]
openjdk-11-jre/cosmic-updates,cosmic-security,now 11.0.1+13-2ubuntu1 amd64 [installed]

And then just got the lein script directly from their website. After running it once and adding it to my path I launch the REPL

In the lein repl :

user=> (System/getProperty "java.specification.version")
"11"
user=> (clojure.reflect/resolve-class (.getContextClassLoader (Thread/currentThread)) 'javafx.application.Platform)

ClassNotFoundException clojure.reflect  java.net.URLClassLoader.findClass (URLClassLoader.java:471)

And when I lein run in my project I get the same errors as before.

Do you have suggestions as to how to debug this further?
And just case it's a problem with my project configuration, is there any example project I can clone and run ? (I'm unclear on how to run examples from packages directly, like the ones here in fn-fx/examples/)

I notice that's given you a headless JDK and JRE again - any chance you could reinstall with a "headed" JDK and/or JRE?

And I'm still intrigued by that ClassNotFoundException - it may be related to the issues we're seeing. What do (clojure-version) and (leiningen.core.main/leiningen-version) give you, when executed in a REPL?

Instructions on how to run the examples are in the README, but I don't think you're going to have much joy until we get past the ClassNotFoundException.

Hmm, that part looks fine

user=> (clojure-version)
"1.8.0"
user=> (leiningen.core.main/leiningen-version)
"2.8.1"

Though when I type in leiningen.co and then hit TAB to autocomplete I get a weird error...

user=> (leiningen.coNullPointerException   complete.core/fn--632/iter--624--633/fn--634 (core.clj:66)

Something must be really messed up with my setup!

Actually I get the same behaviour when I type (leiningen.co and then hit TAB, and am also getting the same output for (clojure-version) and (leiningen.core.main/leiningen-version), so that all lines up nicely.

It's just the output from (clojure.reflect/resolve-class (.getContextClassLoader (Thread/currentThread)) 'javafx.application.Platform) that's different - I get nil from that.

How exasperating!

Yikes. Yeah, I even tried deleting .lein and .m2 and having them redownloaded/rebuild but still the same issue. You are running with OpenJDK 11? The headless/headfull stuff is a bit weird. At least on Ubuntu openjdk-11-jdk includes openjdk-11-jdk-headless as a dependency. So I think it's just a wrapper with the AWT/Swing stuff. But I have like zero experience with the Java ecosystem so it's all new to me (there are more layers to the toolchain cake than with my usual C++ - so I'm still learning)

Well I appreciate your help, but I guess this issue is unrelated to fn-fx. I really appreciate you taking the time to try to help me :)

I'll add a note here if I find a solution

Yeah I have OpenJDK 11 (my default) as well as Oracle JDK 1.8 and OpenJDK 1.8 here, though I'm on macOS rather than Linux. But the TravisCI tests run on Linux - docker at the moment, though they're moving to kvm-based VMs shortly.

I'm at a complete loss as to what might be going on. If I have time I'll spin up a Ubuntu VM and give it a go directly. Sorry I couldn't be of more help!

Thanks! I put up an issue on Lein. I feel it's some setup/interaction between lein and ubuntu and nothing JFX related haha. Hopefully someone there will have something insightful to tell me or at least give me some tips as to where to go next.

Just pray it's not something dumb that I did and I end up with egg on my face :)

I figured out the difference in our output from (clojure.reflect/resolve-class (.getContextClassLoader (Thread/currentThread)) 'javafx.application.Platform), and the even better news is that it was due to my environment, not yours!! 🎉 #eggonmyface

It turns out my ~/.lein/profiles.clj file required clojure.reflect, which loaded the ns. So if you run this, I'm 99% certain you'll get the same output I am (i.e. nil):

(require '[clojure.reflect])   ; Load the ns
(clojure.reflect/resolve-class (.getContextClassLoader (Thread/currentThread)) 'javafx.application.Platform)

So with that mystery out of the way we can get back to troubleshooting your actual issue. First up, did you update your project.clj to use the OpenJFX artifact (i.e. [fn-fx/fn-fx-openjfx11 "0.5.0-SNAPSHOT"]), rather than the JavaFX one, after installing OpenJDK 11? The README explains this in more detail (and yes it's a bit of a hassle, but I haven't yet come up with any way around requiring two artifacts).

Ah, yep! technomancy just told me about the require I was missing haha - and yeah, I forgot about updating my project.clj

Everything is working now! Thanks for all the patience :)

No thank you for your patience! This isn't the first (or, I'm sure, last) time I've been tripped up by my profiles.clj. It's pretty convenient to have customised it, but occasionally it completely blows me out of the water...