1

I am trying to create an app with Scala and the following is my main file:

import java.io.IOException
import scalafx.Includes._
import scalafx.application.JFXApp3
import scalafx.application.JFXApp3.PrimaryStage
import scalafx.scene.Scene
import scalafxml.core.{FXMLView, NoDependencyResolver}

object IDE extends JFXApp3 {
    private val resource = getClass.getResource("resources/IDE.fxml")
    if (resource == null) {
        throw new IOException("[!] Cannot load resource: resources/IDE.fxml")
    }

//    val root: Parent = FXMLView(resource, NoDependencyResolver)
//    val _scene = new Scene(root)
//    _scene.stylesheets += getClass.getResource("resources/style.css").toExternalForm

    override def start(): Unit = {
        stage = new PrimaryStage() {
            title = "IDE"
            scene = new Scene {
                stylesheets add getClass.getResource("resources/style.css").toExternalForm
                root = FXMLView(resource, NoDependencyResolver)
            }
        }
    }
}

And below is some relevant code from Controller.scala:

class Controller(private val tabPane: TabPane, private val outputArea: TextArea, private val outputPane: TabPane, private val treeView: TreeView[File]) {

    private val tabTextMap = mutable.Map[StringProperty, CodeArea]()
    private val openFileSet = mutable.Set[String]()
    private val projectFilesMap = mutable.Map[String, File]()

    private val terminal = (new TerminalBuilder).newTerminal
    terminal.text = "Terminal"
    outputPane.tabs += terminal

    var dir: File = new File("projectRoot")
    treeView.root = nodesForDirectory(dir)
    private val fileChooser: FileChooser = new FileChooser {
        extensionFilters += new ExtensionFilter("Python Files", "*.py")
    }
    fileChooser.setInitialDirectory(dir)

    private def nodesForDirectory(dir: File): TreeItem[File] = {
        val root = new TreeItem[File](new File(dir.getName))
        for (f <- dir.listFiles()) {
            if (f.isDirectory) {
                root.children += nodesForDirectory(f)
            }
            else if (f.getPath.split("\\.").last.equals("py")) {
                projectFilesMap += (f.getName -> f)
                root.children += new TreeItem[File](new File(f.getName))
            }
        }
        root.setExpanded(true)
        root
    }

However, I seem to face the following errors: (Below is the full stack trace shown when running the app)

WARNING: Unsupported JavaFX configuration: classes were loaded from 'unnamed module @41d3c5d1'
Exception in Application start method
Exception in thread "main" java.lang.RuntimeException: Exception in Application start method
    at com.sun.javafx.application.LauncherImpl.launchApplication1(LauncherImpl.java:901)
    at com.sun.javafx.application.LauncherImpl.lambda$launchApplication$2(LauncherImpl.java:196)
    at java.base/java.lang.Thread.run(Thread.java:833)
Caused by: javafx.fxml.LoadException: 
/Users/.../ide/resources/IDE.fxml

    at javafx.fxml.FXMLLoader.constructLoadException(FXMLLoader.java:2707)
    at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2685)
    at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2548)
    at javafx.fxml.FXMLLoader.load(FXMLLoader.java:2516)
    at scalafxml.core.FXMLView$.apply(FXMLView.scala:19)
    at wacc.ide.IDE$$anon$1$$anon$2.<init>(IDE.scala:27)
    at wacc.ide.IDE$$anon$1.<init>(IDE.scala:25)
    at wacc.ide.IDE$.start(IDE.scala:23)
    at scalafx.application.JFXApp3.$anonfun$main$1(JFXApp3.scala:287)
    at scalafx.application.JFXApp3.$anonfun$init$1(JFXApp3.scala:302)
    at scalafx.application.JFXApp3.$anonfun$init$1$adapted(JFXApp3.scala:302)
    at scala.collection.IterableOnceOps.foreach(IterableOnce.scala:575)
    at scala.collection.IterableOnceOps.foreach$(IterableOnce.scala:573)
    at scala.collection.AbstractIterable.foreach(Iterable.scala:933)
    at scalafx.application.JFXApp3.init(JFXApp3.scala:302)
    at scalafx.application.JFXApp3.init$(JFXApp3.scala:302)
    at wacc.ide.IDE$.init(IDE.scala:12)
    at scalafx.application.AppHelper3.start(AppHelper3.scala:33)
    at com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$9(LauncherImpl.java:847)
    at com.sun.javafx.application.PlatformImpl.lambda$runAndWait$12(PlatformImpl.java:484)
    at com.sun.javafx.application.PlatformImpl.lambda$runLater$10(PlatformImpl.java:457)
    at java.base/java.security.AccessController.doPrivileged(AccessController.java:399)
    at com.sun.javafx.application.PlatformImpl.lambda$runLater$11(PlatformImpl.java:456)
    at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:96)
Caused by: java.lang.NullPointerException
    at java.base/java.lang.reflect.Array.getLength(Native Method)
    at scala.collection.ArrayOps$.foreach$extension(ArrayOps.scala:1318)
    at wacc.ide.controllers.Controller$Controller.nodesForDirectory(Controller.scala:72)
    at wacc.ide.controllers.Controller$Controller.<init>(Controller.scala:37)
    at wacc.ide.controllers.Controller.initialize(Controller.scala:20)
    at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2655)
    ... 22 more

Would anyone know the reason for this bug and possible fixes? Any help would be greatly appreciated!

MPP
  • 49
  • 7
  • 2
    For the warning, see [this Q&A](https://stackoverflow.com/q/67854139/6395627). Though I don't know how Scala interacts with the Java Platform Module System (JPMS). As for the exception, you seem to have cut off the important part of the stack trace. Please provide the full error. – Slaw Mar 11 '23 at 21:48
  • Putting `resources/` in your resource path is probably wrong. Probably a duplicate of many [resource lookup questions](https://stackoverflow.com/questions/61531317/how-do-i-determine-the-correct-path-for-fxml-files-css-files-images-and-other). But you may have a strange, non-standard lookup path for your resources, so the path may be ok and you may have a different issue with the fxml or controller code. – jewelsea Mar 12 '23 at 04:35
  • @Slaw The question has been updated with the full stack trace – MPP Mar 12 '23 at 16:27
  • It seems like the warning doesn't affect the app from starting and it is the exception below that breaks the application – MPP Mar 12 '23 at 16:38
  • The error is telling us that the FXML file was found and loaded just fine, but an exception is being thrown in the `initialize` method of `Controller`. Can you show us that class? – Slaw Mar 12 '23 at 18:02
  • @Slaw Many thanks for your reply, I updated my question with the relevant code for `Controller`. The error seems to be due to `dir.listFiles()` being `null`. – MPP Mar 12 '23 at 22:50

1 Answers1

1

Update: Added a null check before the for-loop and this issue seems to be resolved.

MPP
  • 49
  • 7
  • [`File#listFiles()`](https://docs.oracle.com/en/java/javase/19/docs/api/java.base/java/io/File.html#listFiles()) is defined to return `null` "_if this abstract pathname does not denote a directory, or if an I/O error occurs_". From what I can tell, you only call this recursive method on directories, so my guess is that some I/O error is occuring. Honestly, this is one of the pitfalls of `java.io.File`. Many methods only indicate _something_ went wrong, but not _what_ went wrong. I would use the `java.nio.file.*` API if you can—it's superior. – Slaw Mar 12 '23 at 23:59