How to find resources in Kotlin?


#1

I thought I'd find the answer to this, and indeed my code compiles, but I eventually get a runtime error.

Here’s some simple code that tries to create a JavaFX UI from an FXML specification (a resource):

package ui

import kotlinfx.builders.*
import kotlinfx.properties.*
import javafx.application.Application
import javafx.stage.Stage
import javafx.fxml.FXMLLoader

fun main(args: Array<String>) {
  Application.launch(javaClass<LaRGUI>())
}

class LaRGUI : Application() {
  override fun start(stage: Stage?) {
  print(javaClass.getResource(“main.fxml”));
  Stage(stage, title = “Log and Report”) {
           scene = Scene(width = 900.0, height = 550.0) {
           root = FXMLLoader.load(javaClass.getResource(“main.fxml”));
           }
  }.show()
  }
}


Here is the error:


$ ~/gradle-2.3/bin/gradle ui
:compileKotlin
w: Annotations path entry points to a non-existent location:
:compileJava UP-TO-DATE
:processResources
:classes
:jar
:ui
nullException in Application start method
Exception in thread “main” java.lang.reflect.InvocationTargetException
  at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
  at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
  at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
  at java.lang.reflect.Method.invoke(Method.java:483)
  at sun.launcher.LauncherHelper$FXHelper.main(LauncherHelper.java:767)
Caused by: java.lang.RuntimeException: Exception in Application start method
  at com.sun.javafx.application.LauncherImpl.launchApplication1(LauncherImpl.java:875)
  at com.sun.javafx.application.LauncherImpl.lambda$launchApplication$147(LauncherImpl.java:157)
  at com.sun.javafx.application.LauncherImpl$$Lambda$48/99550389.run(Unknown Source)
  at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.NullPointerException: Location is required.
  at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3201)
  at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3169)
  at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3142)
  at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3118)
  at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3098)
  at javafx.fxml.FXMLLoader.load(FXMLLoader.java:3091)
  at ui.LaRGUI$start$1$1.invoke(main.kt:24)
  at ui.LaRGUI$start$1$1.invoke(main.kt:19)
  at kotlinfx.builders.BuildersPackage$Scene$e907cc0b.Scene(Scene.kt:83)
  at kotlinfx.builders.BuildersPackage.Scene(Unknown Source)
  at ui.LaRGUI$start$1.invoke(main.kt:23)
  at ui.LaRGUI$start$1.invoke(main.kt:19)
  at kotlinfx.builders.BuildersPackage$Stage$651bb459.Stage(Stage.kt:48)
  at kotlinfx.builders.BuildersPackage.Stage(Unknown Source)
  at ui.LaRGUI.start(main.kt:22)
  at com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$153(LauncherImpl.java:821)
  at com.sun.javafx.application.LauncherImpl$$Lambda$51/1084860161.run(Unknown Source)
  at com.sun.javafx.application.PlatformImpl.lambda$runAndWait$166(PlatformImpl.java:323)
  at com.sun.javafx.application.PlatformImpl$$Lambda$45/1469821799.run(Unknown Source)
  at com.sun.javafx.application.PlatformImpl.lambda$null$164(PlatformImpl.java:292)
  at com.sun.javafx.application.PlatformImpl$$Lambda$47/781040349.run(Unknown Source)
  at java.security.AccessController.doPrivileged(Native Method)
  at com.sun.javafx.application.PlatformImpl.lambda$runLater$165(PlatformImpl.java:291)
  at com.sun.javafx.application.PlatformImpl$$Lambda$46/626202354.run(Unknown Source)
  at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
  at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
  at com.sun.glass.ui.win.WinApplication.lambda$null$141(WinApplication.java:102)
  at com.sun.glass.ui.win.WinApplication$$Lambda$37/128893786.run(Unknown Source)
  … 1 more
:ui FAILED

I’ve attached an image of my project structure. Also, I verfied main.fxml is getting put into the jar file:

$ unzip LaR.jar
Archive:  LaR.jar
  creating: META-INF/
  inflating: META-INF/MANIFEST.MF
  creating: ui/
  inflating: ui/LaRGUI$start$1$1.class
  inflating: ui/LaRGUI$start$1.class
  inflating: ui/LaRGUI.class
  inflating: ui/UiPackage$main$95ba707c.class
  inflating: ui/UiPackage.class
  inflating: main.fxml

Any ideas what I may be doing wrong? Thanks!



LaR_Resource.PNG (75.8 KB)

#2

See: http://stackoverflow.com/a/22011185


#3

I had actually looked at that page, but didn't see anything very helpful. getClass is apparently replaced by javaClass in Kotlin, which I was able to compile successfuly. I believe I've also put my fxml resource in the designated place.


#4

Have you tried "javaClass.getClassLoader().getResource("main.fxml")" or "javaClass.getResource("/main.fxml")"


#5

Thanks, it was a bit strange to me that getResource existed at two levels; I suppose the way I was using it was trying to get the resource of the javaClass class...

Also, I had to specify the class like this:

 
javaClass<LaRGUI>().getClassLoader().getResource("main.fxml")

I saw some code floading around like this:

Paths.get(javaClass<Unit>().getClassLoader()!!.getResource(".")!!.getPath()!!)!!.
getParent()!!.getParent()!!.getParent()!!.toFile().getAbsolutePath()

Any idea what the double “!” operator is?


#6

Its explained in the documentation: http://kotlinlang.org/docs/reference/null-safety.html#the--operator


#7

This trick does not seems to work now from inside lambdas. Any idea how to get the resources? I am using lambda as part of a dsl.

javaClass.classLoader.getResource("abcd.xyz") always returns null from lambda, but it is returning the resources from a normal top-level class.