shan
shan

Reputation: 3145

java.lang.NoSuchMethodException when trying to run TornadoFX Application

Not sure what is causing it to not find the "init" function on my View, so I thought I'd post here and see if anyone else had this issue.

Everything compiles ok! And then when I run my program I get this error:

java.lang.InstantiationException: com.my.tfx.app.InputView
  at java.lang.Class.newInstance(Class.java:427)
  at tornadofx.FXKt.find(FX.kt:372)
  at tornadofx.FXKt.find$default(FX.kt:358)
  at tornadofx.App.start(App.kt:80)
  at com.my.tfx.app.UserInputUI.start(UserInputUI.kt:15)
  at com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$8(LauncherImpl.java:863)
  at com.sun.javafx.application.PlatformImpl.lambda$runAndWait$7(PlatformImpl.java:326)
  at com.sun.javafx.application.PlatformImpl.lambda$null$5(PlatformImpl.java:295)
  at java.security.AccessController.doPrivileged(Native Method)
  at com.sun.javafx.application.PlatformImpl.lambda$runLater$6(PlatformImpl.java:294)
  at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
  at com.sun.glass.ui.gtk.GtkApplication._runLoop(Native Method)
  at com.sun.glass.ui.gtk.GtkApplication.lambda$null$5(GtkApplication.java:139)
  at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.NoSuchMethodException: com.my.tfx.app.InputView.<init>()
  at java.lang.Class.getConstructor0(Class.java:3082)
  at java.lang.Class.newInstance(Class.java:412)
  ... 13 more

Not quite sure what is causing this.. I have a setup like this:

class UserInputUI : App(InputView(SVGEnum.first, StringEnum.first, UserInput.validationFunctions)::class, UIStyles::class) {
  init {
    reloadStylesheetsOnFocus()
  }

  override fun start(stage: Stage) {
    super.start(stage)
    stage.minWidth = 1024.0
    stage.minHeight = 768.0
    stage.maxWidth = 2560.0
    stage.maxHeight = 1440.0
  }
}

class InputView(val s: SVGEnum, val q: StringEnum, val valFunArray : ArrayList<(String)-> Boolean>) : View() {

  override val root = stackpane {
    //contents ommitted cause they're super long and I dont think its relevant,
    //but I can add it in if requested
  }

}

Any ideas? Or is this a bug? Thanks!

Upvotes: 0

Views: 1085

Answers (1)

Edvin Syse
Edvin Syse

Reputation: 7297

Views must have a no args constructor, so that they can be instantiated by the framework. In your app subclass (UserInputUI) you actually instantiate InputView youtrself and then call ::class to get the KClass of it. You're only supposed to pass it the KClass directly, so you need to modify your code so that UserInputUI is defined like this:

class UserInputUI : App(InputView::class, UIStyles::class)

(I have omitted the init block and the start override. By the way, make sure you don't call reloadStylesheetsOnFocus in production. To make sure that never makes it into production, remove it and set the option in the TornadoFX IDEA Run Configuration istead).

Next, you must make sure that InputView has a noargs constructor. You need to use another technique to pass parameters into it. Since you hard coded them in your App class you might just hard code them directly in InputView as well, or you can introduce a ViewModel that you configure in App.start based on command line parameters or a configuration file if you like.

A rewrite that simply hardcodes the values in InputView instead of UserInputIU would look something like this:

class InputView() : View() {
    val s: SVGEnum = SVGEnum.first
    val q: StringEnum = StringEnum.first
    val valFunArray: ArrayList<(String) -> Boolean> = UserInput.validationFunctions

    override val root = stackpane {
    }
}

I hope that clarifies the issue :)

Upvotes: 4

Related Questions