Clojure is not generating a class

97 Views Asked by At

I created a new Clojure app with clojure -Tclj-new app :name myname/myapp and added the javafx deps to deps.edn

org.openjfx/javafx-controls {:mvn/version "17.0.2"}
org.openjfx/javafx-base {:mvn/version "17.0.2"}
org.openjfx/javafx-graphics {:mvn/version "17.0.2"}
org.openjfx/javafx-media {:mvn/version "17.0.2"}
org.openjfx/javafx-web {:mvn/version "17.0.2"}

I copied the initialization of a UI using JavaFX, extending the class Application.

(ns myname.myapp
  (:import
   (javafx.application Application)
   (javafx.scene Scene)
   (javafx.scene.layout VBox)
   (javafx.scene.control Label)
   (javafx.stage Stage))
  (:gen-class :extends javafx.application.Application))

(def app (atom nil))

(defn -start [this stage]
  (let [root (VBox.)]
    (reset! app this)
    (.setTitle stage "Hello From Clojure!")
    (.add (.getChildren root) (Label. "Hello World"))
    (.show stage)))

(defn -main [& args]
  (Application/launch myname.myapp args))

I cannot run the project. With clj -M:run-m it returns

Syntax error (ClassNotFoundException) compiling at (myname/myapp.clj:20:3). myname.myapp

It seems that Clojure is not generating any class since no folder target is created. I'm using Clojure 1.11.1 on macOS 12.4

2

There are 2 best solutions below

1
Martin Půda On BEST ANSWER

I think you really have to create uberjar- you can also use this command:

lein uberjar

and then use java -jar your-app-standalone.jar in the folder with the created jar (probably target/uberjar/).

Also, if you want to display your Label, you have to create Scene and add that label there. This works:

(ns myapp.core
  (:import
    (javafx.application Application)
    (javafx.scene Scene)
    (javafx.scene.layout VBox)
    (javafx.scene.control Label))
  (:gen-class :extends javafx.application.Application))

(def app (atom nil))

(defn -start [this stage]
  (let [vbox (VBox.)
        scene (Scene. vbox 200 200)]
    (reset! app this)
    (.add (.getChildren vbox) (Label. "Hello World"))
    (doto stage
      (.setTitle "Hello From Clojure!")
      (.setScene scene)
      (.show))))

(defn -main [& args]
  (Application/launch myapp.core (into-array String [])))

Note that there's a wrapper over JavaFX called Cljfx, which would allow you to -among other things- test your project in REPL, without creating any uberjars.

Minimal example:

Dependency: [cljfx "1.7.21"]

Core:

(ns myapp.core
  (:require [cljfx.api :as fx])
  (:gen-class))

(fx/on-fx-thread
  (fx/create-component
    {:fx/type :stage
     :showing true
     :title "Cljfx example"
     :width 300
     :height 100
     :scene {:fx/type :scene
             :root {:fx/type :v-box
                    :alignment :center
                    :children [{:fx/type :label
                                :text "Hello world"}]}}}))
1
dorab On

To compile the app and create an uberjar that you can run, you might want to use the following

clojure -T:build org.corfield.build/uber :lib myname/myapp :main myname.myapp

That should create an uberjar in the target folder. You can then run the uberjar using

java -jar target/myapp-standalone.jar

I haven't used Java FX before so can't help with that.