Hannes
Hannes

Reputation: 5262

OpenJFX application fails to launch using Scala

Launching following application fails with java.lang.NoSuchMethodException: dev.buildingdragons.dragon.Dragon$.<init>() (find the full stack trace below).

To me, it looks like there is a constructor missing, but which? And Why?

I do now there are projects like ScalaFX but before using them I want to fully understand what is going on so I really want to create a walking skeleton.

Environment:

Dragon.scala:

package dev.buildingdragons.dragon

import javafx.application.{Application, Platform}
import javafx.scene.Scene
import javafx.scene.control.Button
import javafx.stage.Stage

object Dragon extends Application {
  def main(args: Array[String]) = Application.launch(args: _*)

  override def start(stage: Stage): Unit = {
    val scene = new Scene(new Button("Test"))

    stage.setTitle("Hello, Dragon!")
    stage.setScene(scene)
    stage.showAndWait()

    Platform.exit()
  }
}

build.gradle:

plugins {
    id 'scala'
    id 'org.openjfx.javafxplugin' version '0.0.7'
}

compileScala.targetCompatibility = 1.8

// In this section you declare where to find the dependencies of your project
repositories {
    mavenCentral()
}

dependencies {
    compile 'org.scala-lang:scala-library:2.12.8'
    compile 'org.scalafx:scalafx_2.12:11-R16'
}

javafx {
    version = "11.0.2"
    modules = ['javafx.controls']
}

Full stack trace:

Exception in Application constructor
Exception in thread "main" java.lang.RuntimeException: Unable to construct Application instance: class dev.buildingdragons.dragon.Dragon$
    at com.sun.javafx.application.LauncherImpl.launchApplication1(LauncherImpl.java:890)
    at com.sun.javafx.application.LauncherImpl.lambda$launchApplication$2(LauncherImpl.java:195)
    at java.base/java.lang.Thread.run(Thread.java:834)
Caused by: java.lang.NoSuchMethodException: dev.buildingdragons.dragon.Dragon$.<init>()
    at java.base/java.lang.Class.getConstructor0(Class.java:3350)
    at java.base/java.lang.Class.getConstructor(Class.java:2152)
    at com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$8(LauncherImpl.java:801)
    at com.sun.javafx.application.PlatformImpl.lambda$runAndWait$12(PlatformImpl.java:455)
    at com.sun.javafx.application.PlatformImpl.lambda$runLater$10(PlatformImpl.java:428)
    at java.base/java.security.AccessController.doPrivileged(Native Method)
    at com.sun.javafx.application.PlatformImpl.lambda$runLater$11(PlatformImpl.java:427)
    at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:96)
    at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
    at com.sun.glass.ui.win.WinApplication.lambda$runLoop$3(WinApplication.java:174)
    ... 1 more

EDIT: As suggested by eugene-ryzhikov I modified Dragon.scala:

package dev.buildingdragons.dragon

import javafx.application.{Application, Platform}
import javafx.scene.Scene
import javafx.scene.control.Button
import javafx.stage.Stage

class Dragon extends Application {
  override def start(stage: Stage): Unit = {
    val scene = new Scene(new Button("Test"))

    stage.setTitle("Hello, Dragon!")
    stage.setScene(scene)
    stage.showAndWait()

    Platform.exit()
  }
}

object Dragon {
  def main(args: Array[String]) = Application.launch(classOf[Dragon],  args: _*)
}

That solved the original problem but now I ran into the problem I was afraid of: Java's Project Jigsaw:

Exception in Application start method
java.lang.reflect.InvocationTargetException
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:566)
    at javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplicationWithArgs(LauncherImpl.java:464)
    at javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplication(LauncherImpl.java:363)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:566)
    at java.base/sun.launcher.LauncherHelper$FXHelper.main(LauncherHelper.java:1051)
Caused by: java.lang.RuntimeException: Exception in Application start method
    at javafx.graphics/com.sun.javafx.application.LauncherImpl.launchApplication1(LauncherImpl.java:900)
    at javafx.graphics/com.sun.javafx.application.LauncherImpl.lambda$launchApplication$2(LauncherImpl.java:195)
    at java.base/java.lang.Thread.run(Thread.java:834)
Caused by: java.lang.IllegalAccessError: superclass access check failed: class com.sun.javafx.scene.control.ControlHelper (in unnamed module @0x4e08e183) cannot access class com.sun.javafx.scene.layout.RegionHelper (in module javafx.graphics) because module javafx.graphics does not export com.sun.javafx.scene.layout to unnamed module @0x4e08e183
    at java.base/java.lang.ClassLoader.defineClass1(Native Method)
    at java.base/java.lang.ClassLoader.defineClass(ClassLoader.java:1016)
    at java.base/java.security.SecureClassLoader.defineClass(SecureClassLoader.java:174)
    at java.base/jdk.internal.loader.BuiltinClassLoader.defineClass(BuiltinClassLoader.java:802)
    at java.base/jdk.internal.loader.BuiltinClassLoader.findClassOnClassPathOrNull(BuiltinClassLoader.java:700)
    at java.base/jdk.internal.loader.BuiltinClassLoader.loadClassOrNull(BuiltinClassLoader.java:623)
    at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:581)
    at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:178)
    at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521)
    at javafx.scene.control.Control.<clinit>(Control.java:86)
    at dev.buildingdragons.dragon.Dragon.start(Dragon.scala:10)
    at javafx.graphics/com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$9(LauncherImpl.java:846)
    at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runAndWait$12(PlatformImpl.java:455)
    at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$10(PlatformImpl.java:428)
    at java.base/java.security.AccessController.doPrivileged(Native Method)
    at javafx.graphics/com.sun.javafx.application.PlatformImpl.lambda$runLater$11(PlatformImpl.java:427)
    at javafx.graphics/com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:96)
    at javafx.graphics/com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
    at javafx.graphics/com.sun.glass.ui.win.WinApplication.lambda$runLoop$3(WinApplication.java:174)
    ... 1 more
Exception running application dev.buildingdragons.dragon.Dragon

I believe that is due to the fact that Scala does not enforce module restrictions at compile time but the JVM does at runtime.

Upvotes: 2

Views: 191

Answers (1)

Eugene Ryzhikov
Eugene Ryzhikov

Reputation: 17359

That error is the consequence of having your start method within the object. Move it to the new Dragon class with main method in the companion Dragon object. Also use the launch method where you can pass the application class.

Upvotes: 4

Related Questions