"Unable to resolve class" problem when compiling a Groovy-JavaFX program

1,177 views
Skip to first unread message

Andrea Cisternino

unread,
Sep 14, 2014, 6:07:41 AM9/14/14
to gradl...@googlegroups.com
Hi All,

I recently started exploring Groovy and I decided to write a small application using JavaFX for the GUI layer.
I am using Oracle JDK 8, Groovy 2.3 and Gradle 2.1.

My first experiment was quite minimalistic: I converted the JavaFX Hello World example from Oracle [1] to Groovy
and created a very simple Gradle project to compile the code.
The project is available on GitHub [2].

Unfortunately, when compiling the code, I get an error:

 [andrea@sirio hellofx-groovy-gradle]$ gradle clean build
 :clean
 :compileJava UP-TO-DATE
 :compileGroovy
 startup failed:
 /path/to/hellofx-groovy-gradle/src/main/groovy/helloworld/HelloWorldFx.groovy: 5: unable to resolve class javafx.scene.control.Button
  @ line 5, column 1.
    import javafx.scene.control.Button
    ^

and more like the above for the other JavaFX classes.

I then tried to compile the same source code from the command line using the `groovyc` Groovy compiler and it worked flawlessly.
I also tried an equivalent "pure Java" project using the original program from the Oracle page and even in this case everything worked OK.

To recap: only when compiling Groovy code with Gradle, the JavaFX classes are not visible.

This is what I have found going down this rabbit hole :)

JavaFX packages are contained in a separate jfxrt.jar archive unlike e.g. Swing that is contained in the main rt.jar archive.

The way the jfxrt.jar archive is made available to Java applications differs between JVM versions and vendors:

  • Oracle JDK 7
    jfxrt.jar is in ${java.home}/lib and therefore not available by default on the classpath.
    Java 7 projects that want to use JavaFX must explicitly find and add jfxrt.jar to the compile
    and runtime classpath.

  • Oracke JDK 8 & 9
    jfxrt.jar is in ${java.home}/lib/ext and is made available to Java programs via the
    Extension Classloader that lies at the core of the Extension Mechanism [3].
    Regular java programs (including the `javac` and `groovyc` compilers) have direct access
    to the JavaFX classes with no need to fiddle with the classpath.

  • OpenJDK 7
    JavaFX is not available in this JVM.

  • OpenJDK 8 & 9
    JavaFX is currently not available in any OpenJDK build, but it could be theoretically included
    in the future because the OpenJFX project [4] is now open source. It is up to whoever builds
    a specific OpenJDK release to also include OpenJFX.
I was able to track down the issue with Gradle to the configuration of the classloader provided to the JavaAwareCompilationUnit
instance created in the class org.gradle.api.internal.tasks.compile.ApiGroovyCompiler.

The classloader (local variable "compileClasspathClassLoader" in the ApiGroovyCompiler.execute() method) is built without
the ExtClassLoader as one of its ancestors and therefore it bails out when it tries to load a JavaFX class.

I have implemented a simple fix [5] in ApiGroovyCompiler that adds the Extension Classloader as an ancestor of the compile classloader
only when JavaFX is available, therefore maintaining the previous behaviour when it is not.

Before I submit a PR I'd love to have some feedback on whether you think this is really an issue and on how I proceeded to fix it.

For reference there is a forum post and an associated bug that have probably the same root cause: [6] [7].

I hope this helps.
BTW, Thanks for a fantastic tool!

Andrea.

[1] http://docs.oracle.com/javase/8/javafx/get-started-tutorial/hello_world.htm
[2] https://github.com/acisternino/helloworld-fx
[3] http://docs.oracle.com/javase/tutorial/ext/index.html
[4] http://openjdk.java.net/projects/openjfx
[5] https://github.com/acisternino/gradle/commit/f53837584b2c9d9b65ce15089a00a534d8092260
[6] http://forums.gradle.org/gradle/topics/noclassdeffounderror_on_a_javafx_class_in_compilegroovy_task_on_java_8
[7] http://issues.gradle.org//browse/GRADLE-3046

Adam Murdoch

unread,
Sep 14, 2014, 2:46:57 PM9/14/14
to gradl...@googlegroups.com
Thanks for digging into this. Your fix looks good to me.

Would you mind adding an integration test case? Take a look at BasicGroovyCompilerIntegrationSpec and perhaps add a test case there. You can mark a test case with @Requires(TestPrecondition.JDK8_OR_LATER) and it will only run on the appropriate java versions.

--
You received this message because you are subscribed to the Google Groups "gradle-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email to gradle-dev+...@googlegroups.com.
To post to this group, send email to gradl...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/gradle-dev/e4f5c9ff-51e2-45bf-ab31-462c9f141cde%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


--
Adam Murdoch
Gradle Co-founder
http://www.gradle.org
CTO Gradleware Inc. - Gradle Training, Support, Consulting
http://www.gradleware.com



Andrea Cisternino

unread,
Sep 15, 2014, 3:18:49 AM9/15/14
to gradl...@googlegroups.com
Hi Adam,

Thanks for the thumbs-up.
I'll try to add some integration tests asap and then issue a PR for an official review of my work.

Andrea.

--
You received this message because you are subscribed to a topic in the Google Groups "gradle-dev" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/gradle-dev/q3u-T09km2s/unsubscribe.
To unsubscribe from this group and all its topics, send an email to gradle-dev+...@googlegroups.com.

To post to this group, send email to gradl...@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.



--
Andrea Cisternino, Erlangen, Germany
LinkedIn: http://www.linkedin.com/in/andreacisternino
GitHub: http://github.com/acisternino

Andrea Cisternino

unread,
Oct 1, 2014, 8:16:20 AM10/1/14
to gradl...@googlegroups.com
Hi all,

For future reference, I have added integration tests and created a Pull Request on GitHub.

It is here:  https://github.com/gradle/gradle/pull/332

Thanks,
  Andrea.
To unsubscribe from this group and stop receiving emails from it, send an email to gradle-dev+unsubscribe@googlegroups.com.

To post to this group, send email to gradl...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/gradle-dev/e4f5c9ff-51e2-45bf-ab31-462c9f141cde%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


--
Adam Murdoch
Gradle Co-founder
http://www.gradle.org
CTO Gradleware Inc. - Gradle Training, Support, Consulting
http://www.gradleware.com



--
You received this message because you are subscribed to a topic in the Google Groups "gradle-dev" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/gradle-dev/q3u-T09km2s/unsubscribe.
To unsubscribe from this group and all its topics, send an email to gradle-dev+unsubscribe@googlegroups.com.

To post to this group, send email to gradl...@googlegroups.com.

rebecca godawatte

unread,
Aug 5, 2016, 12:43:16 AM8/5/16
to gradle-dev

Hi Andrea Cisternino,

Thank you very much for the salution given [6] http://forums.gradle.org/gradle/topics/noclassdeffounderror_on_a_javafx_class_in_compilegroovy_task_on_java_8

Cheers,
Rebecca
Reply all
Reply to author
Forward
0 new messages