IntelliJ doesn't load javafx packages from Maven dependencies (JavaFX 17) - java

I'm trying to get a Maven/JavaFX project, created from the javafx-archetype-fxml archetype and unedited, to run in the latest version of IntelliJ. To be clear, the project is a direct copy of that archetype; I'm just trying to get an example working.
Suffice it to say I'm a complete beginner with Maven, so I'm could just be missing an obvious step here.
Maven build went smoothly, and the project's pom.xml looks the way the JavaFX documentation says it should.
I left it unchanged except for updating the maven.compiler.source and maven.compiler.target properties, as well as the release property in the maven-compiler-plugin, to 16, the JDK version I'm using for the project:
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-
v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.epre</groupId>
<artifactId>jfx-sandbox</artifactId>
<version>0.0.1-SNAPSHOT</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>16</maven.compiler.source>
<maven.compiler.target>16</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-controls</artifactId>
<version>17</version>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-fxml</artifactId>
<version>17</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
<configuration>
<release>16</release>
</configuration>
</plugin>
<plugin>
<groupId>org.openjfx</groupId>
<artifactId>javafx-maven-plugin</artifactId>
<version>0.0.6</version>
<executions>
<execution>
<!-- Default configuration for running -->
<!-- Usage: mvn clean javafx:run -->
<id>default-cli</id>
<configuration>
<mainClass>com.epre.App</mainClass>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
The dependencies show up in the Maven tab, and I'm able to reload the project with no problems. Similarly, I can see that the javafx-base, -controls, -fxml, -graphics, and their corresponding :win libraries have been added to the project's External Libraries (pic):
However, when I try to run the project's Main class, IntelliJ throws ~15 errors telling me that many of the packages I'm trying to import from don't exist.
java: package javafx.application does not exist
java: package javafx.fxml does not exist
java: package javafx.scene does not exist
java: package javafx.scene does not exist
java: package javafx.stage does not exist
java: cannot find symbol class Application
java: cannot find symbol class Scene
java: method does not override or implement a method from a supertype
java: cannot find symbol class Stage
java: cannot find symbol class Scene
java: cannot find symbol class Parent
java: cannot find symbol class FXMLLoader
java: cannot find symbol class FXMLLoader
java: cannot find symbol method launch()
This is the Main class, just to show what sort of packages I'm trying to import from:
package com.epre;
import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;
import java.io.IOException;
/**
* JavaFX App
*/
public class App extends Application {
private static Scene scene;
#Override
public void start(Stage stage) throws IOException {
scene = new Scene(loadFXML("primary"), 640, 480);
stage.setScene(scene);
stage.show();
}
static void setRoot(String fxml) throws IOException {
scene.setRoot(loadFXML(fxml));
}
private static Parent loadFXML(String fxml) throws IOException {
FXMLLoader fxmlLoader = new FXMLLoader(App.class.getResource(fxml + ".fxml"));
return fxmlLoader.load();
}
public static void main(String[] args) {
launch();
}
}
I've done some searching and tried fixing every unrelated problem with the project, just to try and isolate the issue, i.e.
Changing the project language level to 16
Changing the project module's Per-module bytecode version to 16
Replacing instances of "11" in the pom.xml with "16" as mentioned earlier
Opening the project in an older version of IntelliJ
None of these have produced any change, though.
In previous non-Maven projects that also used JavaFX, I had to add all the packages the project needed to its module-info.java. This is the only step I can think of that I haven't taken, since it's my understanding that I shouldn't have to deal with it if I'm declaring those packages as dependencies in the pom.xml?
EDIT: I'm assuming I don't need to set up a module-info.java because the JavaFX documentation never mentions it as a step for creating a Maven+JavaFK project: https://openjfx.io/openjfx-docs/.
The JavaFX and IntelliJ > Non-modular with Maven section of the documentation simply states that upon loading the project, "The JavaFX classes will be recognized."
EDIT 2: I managed to solve the package errors and get the program running by changing the JavaFX dependencies in the pom.xml to version 16 instead of 17. Not sure why a single version would break the program like it did, though I suspect there was probably a change in how JavaFX is bundled/distributed.

Update for JavaFX 17.0.0.1 release
The release of JavaFX 17.0.0.1 has resolved this issue and, when using JavaFX and Maven this is the version that should be used instead of 17 (which remains broken in Maven).
When defining a dependency on JavaFX 17 using Maven, ensure that the version defined for JavaFX dependencies is not 17 and is at least 17.0.0.1. Here is an example of a working dependency definition for JavaFX 17.0.0.1 Maven modules.
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-controls</artifactId>
<version>17.0.0.1</version>
</dependency>
Info on release versions and contents and the version number for the current latest release is available in the JavaFX release notes hosted at gluon.
For now, I will leave the rest of the original answer, which discusses some of the background information, as it was when it was originally created.
Maven modules for JavaFX versions prior to 17 (e.g. 16), still continue to function without issue. However, if you have the ability to upgrade and use JavaFX 17.0.0.1 or higher for your application, I encourage this.
JavaFX 17 will be maintained as a stable long-term release of JavaFX. It will maintain a stable feature set and receive bug and security fix support for many years.
Background
I was able to replicate this issue.
This is a known issue only affecting projects which rely on the initial JavaFX 17 release artifacts currently available in the Maven central repository.
See related question:
JavaFX lib can not be build any more since JavaFX 17
Discussion of the issue on the openjfx-dev mailing list:
https://mail.openjdk.java.net/pipermail/openjfx-dev/2021-September/031934.html
Workaround
One current workaround is, if your application relies on JavaFX artifacts from Maven central, to use JavaFX 16 rather than JavaFX 17 until this issue is fixed.
As this is quite a critical issue with the JavaFX 17 release, I would expect it will likely be addressed in an update to the JavaFX 17 release in the near future.
Environment
Mac OS (Catalina) 10.15.7
$ java -version
openjdk version "16.0.2" 2021-07-20
OpenJDK Runtime Environment Temurin-16.0.2+7 (build 16.0.2+7)
OpenJDK 64-Bit Server VM Temurin-16.0.2+7 (build 16.0.2+7, mixed mode, sharing)
IntelliJ IDEA 2021.2 (Ultimate Edition)
Build #IU-212.4746.92, built on July 27, 2021
Steps to replicate
In Idea create a new JavaFX Project
Select New | Project
Choose JavaFX in the left tab.
Choose Language: Java, Build System: Maven, Project SDK: 16
Select Next -> Finish
Test the new project.
Right click on HelloApplication and select Run 'HelloApplication.main()'
The application should run and display a JavaFX application window with a "Hello!" button.
Change the JavaFX version
Edit pom.xml
Change the JavaFX dependency versions from 16 to 17
maven-compiler-plugin version can stay at 16.
In the Maven tab, click the refresh icon to "Reload All Maven Projects"
Test the updated project.
Right click on HelloApplication and select Run 'HelloApplication.main()'
Execution will now fail with the error message:
java: package javafx.fxml does not exist

Related

How can I create an all-in-one jar for a JavaFX project with the Maven Assembly plugin?

I have a very simple Java class, src/main/java/webbrowser/WebBrowser.java:
package webbrowser;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.web.WebView;
import javafx.scene.web.WebEngine;
import javafx.stage.Stage;
public class WebBrowser extends Application {
#Override
public void start(Stage stage) {
WebView browser = new WebView();
WebEngine webEngine = browser.getEngine();
webEngine.load("http://www.oracle.com");
Scene scene = new Scene(browser, 1200, 900);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch();
}
}
I have a pom.xml file that lists the JavaFX dependencies and configures the assembly plugin:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>webbrowser</groupId>
<artifactId>WebBrowser</artifactId>
<packaging>jar</packaging>
<version>1.0-SNAPSHOT</version>
<name>WebBrowser</name>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>17</maven.compiler.source>
<maven.compiler.target>17</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-web</artifactId>
<version>18-ea+9</version>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-controls</artifactId>
<version>18-ea+9</version>
</dependency>
</dependencies>
<build>
<finalName>WebBrowser</finalName>
<pluginManagement>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
</execution>
</executions>
<configuration>
<archive>
<manifest>
<mainClass>
webbrowser.WebBrowser
</mainClass>
</manifest>
</archive>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
</plugin>
</plugins>
</pluginManagement>
</build>
</project>
When I run on the command-line, mvn clean install assembly:single, it says "BUILD SUCCESS" and there are no warnings or errors in the log.
Then I run:
% java -jar target/WebBrowser-jar-with-dependencies.jar
Error: JavaFX runtime components are missing, and are required to run this application
For some reason, the mvn assembly:single plugin did not include every JavaFX dependency.
However, when I run this on the command-line, it works fine and launches the application:
% java --module-path $JAVAFX --add-modules javafx.controls,javafx.web -jar target/WebBrowser-jar-with-dependencies.jar
Questions
Why does the assembly:single goal not package the javafx.controls and javafx.web dependencies inside target/WebBrowser-jar-with-dependencies.jar?
How can I configure the Assembly plugin to include the javafx.controls and javafx.web dependencies inside an all-in-one, runnable target/WebBrowser-jar-with-dependencies.jar file?
Recommended: Change your packaging approach
Don't try to create a single jar for your application.
There are links to packaging resources under the:
javafx tag info.
I suggest you review the information there, then choose and implement an appropriate (and different) packaging solution for your application.
Understanding the error message: JavaFX runtime components are missing
It means the JavaFX runtime is not accessible to your application. JavaFX modules should be on your module path, which is currently not possible if you put them in your application jar.
See the Eden coding tutorial for some information on this and some basic solutions (though it does not cover packaging apps in general as that is a very complex topic):
JavaFX runtime components are missing.
To address your specific questions
1 Why javafx dependencies aren't in the jar-with-dependencies.jar
I copied your code and tried it locally on a Windows machine with OpenJDK 17.
A jar-with-dependencies was built and the javafx Windows libraries were included in the jar. You can see this by running jar tvf on the jar file. It includes both the JavaFX platform class files and the Windows native DLLs.
But when the jar was built, there was an info message:
[INFO] module-info.class already added, skipping
This is key. Each modular JavaFX jar has its own module-info file which is required for it to function in a modular environment. When some are skipped, then the modularity is broken, and the app will no longer run off the module path.
It would be nice if the Maven assembly plugin was clever enough to recognize modular jars are in the dependencies and explicitly warn about that when asked to create a single jar-with-dependencies, because the java runtime does not currently support multi-module jars.
To understand more about why you can't currently put multiple Java platform modules in a single jar, see:
Multiple Java 9 modules from a single Maven module?
2 Creating a jar-with-dependencies
You could switch from the assembly plugin to the shade plugin and use the solution at:
Maven Shade JavaFX runtime components are missing
But you don't have to, you can continue using the assembly plugin for this if that is what you really want to do.
If you do so, understand the warning in the link that then you are running JavaFX in an unsupported configuration off the classpath rather than the module path.
To do this with an assembly:
Add a launcher class to trick the JavaFX runtime into allowing itself to run from the classpath instead of the module path.
package webbrowser;
public class WebBrowserLauncher {
public static void main(String[] args) {
WebBrowser.main(args);
}
}
Change the main class defined for your assembly to reference the new class:
<mainClass>
webbrowser.WebBrowserLauncher
</mainClass>
If you want to allow the app to run on different operating systems than the one you are building it on, then add dependencies for those platforms to your pom.xml. For an example of the additional dependencies required, see:
Maven Shade JavaFX runtime components are missing
I made changes 1&2 and tested them and your app packaged this way ran for me. I didn't bother with change 3 as I can't easily test that at this time.
Execution command and output:
java -jar target/WebBrowser-jar-with-dependencies.jar
Jan 21, 2022 7:59:51 PM com.sun.javafx.application.PlatformImpl startup
WARNING: Unsupported JavaFX configuration: classes were loaded from 'unnamed module #41dc7fe'
The warning exists because JavaFX is being loaded from the classpath rather than the module path.
Assembling multiple jars into a zip or tar archive
Assembly could still be a useful plugin to use in your build process, but for a different purpose.
If you did want to stick with an assembly approach, you could:
Create a jar without dependencies.
Use the assembly to create a lib directory containing your dependencies and the JavaFX modules for the platforms you need to support.
Provide a platform-specific script to launch the app, which appropriately configures the classpath and the module path to use the library dependencies extracted from the archive.
This is a convenience as the user could type the full command into the command line, though that would probably be more painful than just executing a script.
You can then create a custom assembly that includes all of those things in a tar or zip file.
The user would then be able to decompress your archive and use your launcher script to run the app (as long as they had an appropriate JVM preinstalled).
Assembly would be good for that, but jlink or jpackage may be preferred alternatives regardless as those options don't require a preinstalled JVM.
The openjfx-maven-plugin has a similar option in its jlink feature but includes a linked java runtime:
jlinkZipName: When set, creates a zip of the resulting runtime image.
Beside jewelsea's perfect answer, here is a minimal gradle approach that just works... (for the OS you use, with an executable webbrowser-all.jar)
build.gradle
plugins {
id 'application'
id 'org.openjfx.javafxplugin' version '0.0.11'
id 'com.github.johnrengelman.shadow' version '7.1.2'
}
repositories {
mavenCentral()
}
application {
mainClass = 'webbrowser.Launch'
}
javafx {
modules = [ 'javafx.controls', 'javafx.web']
version = '18+'
}
shadowJar {
baseName = 'webbrowser'
classifier = 'all'
}
Add a launcher Launch.java
package webbrowser;
import javafx.application.Application;
public class Launch {
public static void main(String[] args) {
Application.launch(WebBrowser.class, args);
}
}
And your WebBrowser.java
package webbrowser;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.web.WebEngine;
import javafx.scene.web.WebView;
import javafx.stage.Stage;
public class WebBrowser extends Application{
#Override
public void start(Stage stage) {
WebView browser = new WebView();
WebEngine webEngine = browser.getEngine();
webEngine.load("http://www.oracle.com");
Scene scene = new Scene(browser, 1200, 900);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
launch();
}
}

JavaFX as MavenDependency - jar starts on Oracle JDK but not on openJDK

I'm about to finish my master thesis. The program, i developed, is a maven project with javaFx declared as dependencies
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-fxml</artifactId>
<version>16-ea+4</version>
</dependency>
<dependency>
<groupId>org.ow2.asm</groupId>
<artifactId>asm-util</artifactId>
<version>8.0.1</version>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-base</artifactId>
<version>16-ea+4</version>
</dependency>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-controls</artifactId>
<version>16-ea+4</version>
</dependency>
When I'm creating the jar using Maven-install the program runs on Oracle-JDK. But on openJDK it throws a java.lang.ClassNotFoundException.
My understanding is, that javaFX is not included in both JDKs anymore. Thats why I'm unsing maven and build the jar with all dependencies. That way it should find javaFx and start the program regardless the used JDK.
Assuming my assumption is correct that the error has something to do with javaFX.
To compile the Program I'm using JavaSE 13. It runs perfectly using Oracle JDK 15. But it throws a java.lang.ClassNotFoundException using openJDK 14 or 15.
---EDIT---
I'm not totaly sure if this error is regarded to JavaFX.
I'm starting the jar on the console with
java -jar "C:...\test.jar"
This works on the OracleJDK but not on the openJDK. Then the Console prinst:
Error: Could not find or load main class C:\...\test
Caused by: java.lang.ClassNotFoundException: C:\...\test
I know how to print the stacktrace, using the IDE. But is it possible to print the stacktrace using the console in this case?
If so I will do it an edit this question to provide more info.
I would be so grateful for your help. I panic ^^
You are only providing us with some fragments of your setup. So it is difficult to give any specific advice. From what I see I'd say that your program cannot work on any Java which does not contain JavaFX because you do not provide the required arguments in your launch command. Have a look here for proven ways to launch JavaFX correctly: https://openjfx.io/openjfx-docs/
Do you have a MANIFEST.MF file? IT should point towards the class that has your public static void main(String[] args) method <-- Your main method.
Example:
MANIFEST.MF
Manifest-Version: 1.0
Main-Class: classes.TestClass
Helpful stackoverflow: Could not find or load main class with a Jar File
https://taylorial.com/cs1021/Jar.htm#jarwithjavafxpackagesincluded
my Prof just responded and says that it was just a typo in his commandline.
It works perfectly fine.
I will delete this question in view hours, cause it is not really a problem.
Thank you very much.

Trying to run libGDX with Maven and Eclipse

Maybe a newbie question...
I've been working on a LWJGL project, where I use Maven to manage dependencies. In it, I want to use some parts of the libgdx library. So I figured I will first run at least a helloworld working with it before I add it to my main project.
So in my pom.xml I have this:
<!-- https://mvnrepository.com/artifact/com.badlogicgames.gdx/gdx-backend-lwjgl -->
<dependency>
<groupId>com.badlogicgames.gdx</groupId>
<artifactId>gdx-backend-lwjgl</artifactId>
<version>1.9.11</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/com.badlogicgames.gdx/gdx-platform -->
<dependency>
<groupId>com.badlogicgames.gdx</groupId>
<artifactId>gdx-platform</artifactId>
<version>1.9.11</version>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/com.badlogicgames.gdx/gdx -->
<dependency>
<groupId>com.badlogicgames.gdx</groupId>
<artifactId>gdx</artifactId>
<version>1.9.11</version>
</dependency>
The other contents of the file are the same as in a working project and are 100% working.
I tried creating a separate libgdx project before that and... it didn't work. But, I saw that the code that was supposed to run the program was:
public static void main (String[] arg) {
LwjglApplicationConfiguration config = new LwjglApplicationConfiguration();
new LwjglApplication(new SomeApplicationListenerFile(), config);
}
So I used that in my maven project.
When I do "run as a Java Application", the error is the following:
Exception in thread "main" java.lang.NoClassDefFoundError: com/badlogic/gdx/backends/lwjgl/LwjglApplicationConfiguration
at org.boby.RayTracing.main.Main.main(Main.java:179)
And if I do a Maven Build, it tells me that "package com.badlogic.gdx.backends.lwjgl does not exist"
I looked for that package in the jars Maven downloaded in the "Maven dependencies" folder and I found it in gdx-backend-lwjgl-1.9.11.jar - right where it should be.
The package is apparently there, but Java cannot find it. How can I fix that?
Some additional information:
Windows 10, eclipse oxygen, Maven 3.6.0, JRE 1.8.0_191, JDK 8
Thank you in advance! I've been banging my head on this for hours.
Edit: I made some progress. Looks like the "test" was messing things up so I removed those statements. Now I get the following Error:
Exception in thread "main" com.badlogic.gdx.utils.GdxRuntimeException: Couldn't load shared library 'gdx64.dll' for target: Windows 10, 64-bit
at com.badlogic.gdx.utils.SharedLibraryLoader.load(SharedLibraryLoader.java:125)
at com.badlogic.gdx.utils.GdxNativesLoader.load(GdxNativesLoader.java:33)
at com.badlogic.gdx.backends.lwjgl.LwjglNativesLoader.load(LwjglNativesLoader.java:47)
at com.badlogic.gdx.backends.lwjgl.LwjglApplication.<init>(LwjglApplication.java:83)
at com.badlogic.gdx.backends.lwjgl.LwjglApplication.<init>(LwjglApplication.java:71)
at org.boby.RayTracing.main.Main.main(Main.java:178)
It looks like I need to include gdx-natives.jar in my dependencies, but I can't find a maven repository for it.
I downloaded gdx-natives.jar (saw it in a forum thread). In there, was a file named "gdx-64.dll". As I need "gdx64.dll", I just renamed the dll and now it runs.
You can let Maven do the work if you define the gdx-platform dep like this:
<dependency>
<groupId>com.badlogicgames.gdx</groupId>
<artifactId>gdx-platform</artifactId>
<version>1.9.11</version>
<classifier>natives-desktop</classifier>
</dependency>
This will load the natives jar including the gdx64.dll so you don't have to add any external jar to your project in the build path.
A side note is: if you use the standard Maven repo directory structure and you load assets with the Gdx.files.internal("fileName") statement you need to define a folder in the main/repository with the same name as the package you have your code in. (i.e. main/java/myPackage relates to /main/repository/myPackage). I struggled a bit with this because I don't normaly have to define a package folder int the repository dir.

Can Kotlin controller class access Java service class in spring boot

I a working on a project in spring boot .. is it possible to use in kotlin and java both in spring-boot project.
I have tried by making a Kotlin #controller class and calling java #service class but it isn't working
Yes, it will definitely work
You simply need to configure it properly
check your build.gradle source sets and targets
Follow the below folder structure
src
main
java
kotlin
resources
I have done the following to successfully use Kotlin in my existing Spring Boot App.
My IDE is IntelliJ.
(1)
Ensure that Kotlin plugin is installed in the IDE.
Select Tools -> Kotlin -> Configure Kotlin Plugin Updates.
In the Update channel list, select the Stable channel.
Click Check again. The latest Stable build version appears.
Click Install. Apply / OK.
(2)
Get the required dependencies.
Open Spring Initializr (https://start.spring.io/).
Select language as Kotlin.
Keep other things as usual. Here we are doing it for Maven Project.
Click on Explore. Sample pom.xml will appear.
Now copy the following from the sample pom.xml to the pom.xml of your existing Spring Boot Project.
…
<properties>
…
<kotlin.version>1.6.10</kotlin.version>
<!--Edit the version to the latest stable version, if applicable-->
</properties>
…
<dependencies>
…
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-reflect</artifactId>
</dependency>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-stdlib-jdk8</artifactId>
</dependency>
</dependencies>
…
<build>
<sourceDirectory>${project.basedir}/src/main/kotlin</sourceDirectory>
<testSourceDirectory>${project.basedir}/src/test/kotlin</testSourceDirectory>
…
</build>
…
<plugins>
…
<plugin>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-plugin</artifactId>
<configuration>
<args>
<arg>-Xjsr305=strict</arg>
</args>
<compilerPlugins>
<plugin>spring</plugin>
</compilerPlugins>
</configuration>
<dependencies>
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-allopen</artifactId>
<version>${kotlin.version}</version>
</dependency>
</dependencies>
</plugin>
</plugins>
(3)
Create the required directories in your project.
In the src/main directory of your project, create a new directory and name it as kotlin (this directory should be at the same level as src/main/java)
Now right click this directory -> Mark Directory as -> Sources Root
Also, in the src/test directory of your project, create a new directory and name it as kotlin (this directory should be at the same level as src/test/java)
Now right click this directory -> Mark Directory as -> Test Sources Root
(4)
Now update / rebuild the project.
If any Maven / build errors show up then do one / all of the following:
Right click pom.xml -> Maven -> Download sources and documentation
Right click pom.xml -> Maven -> Generate sources and update folders
Right click pom.xml -> Maven -> Reload project
(5)
Now you can create a Kotlin class under the src/main/kotlin package.
For this,
Right click the package -> New -> Kotlin Class/File
Give the class some name and double click Class
Note:
If the newly created Kotlin class does not have a package statement then it will not be visible from your Java classes.
To fix this,
Go to your Java class which has the main method. (This is the class which is annotated by #SpringBootApplication)
Copy the package statement of this class. This should most likely be the first statement of the Java class and should be something like
package com.xyz.myApplication;
Paste this statement in the Kotlin class so that this becomes the first statement of your Kotlin class as well.
Once everything is done, you can simply import and instantiate your Kotlin classes from inside your Java classes.
You can also do vice versa, that is, import and instantiate your Java classes from inside your Kotlin classes.

Different behaviour between Maven & Eclipse to launch a JavaFX 11 app

I'm starting to dig into Java 11 migration for a large app (includes Java FX parts) and I need your help to understand the difference between Maven (3.5.4) on the command-line and Eclipse (2018-09 with Java11 upgrade).
I have a simple Java 11 class
import java.util.stream.Stream;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.stage.Stage;
public class HelloFX extends Application {
#Override
public void start(Stage stage) {
String javaVersion = System.getProperty("java.version");
String javafxVersion = System.getProperty("javafx.version");
Label l = new Label("Hello, JavaFX " + javafxVersion + ", running on Java " + javaVersion + ".");
Scene scene = new Scene(l, 640, 480);
stage.setScene(scene);
stage.show();
}
public static void main(String[] args) {
Stream.of("jdk.module.path",
"jdk.module.upgrade.path",
"jdk.module.main",
"jdk.module.main.class").forEach(key -> System.out.println(key + " : " + System.getProperty(key)));
Application.launch();
}
}
and a simple pom
<project xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.gluonhq</groupId>
<artifactId>hellofx</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.openjfx</groupId>
<artifactId>javafx-controls</artifactId>
<version>11</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
<configuration>
<release>11</release>
</configuration>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>1.2.1</version>
<executions>
<execution>
<goals>
<goal>java</goal>
</goals>
</execution>
</executions>
<configuration>
<mainClass>HelloFX</mainClass>
</configuration>
</plugin>
</plugins>
</build>
</project>
When I run 'mvn compile exec:java' I think nothing uses the new module-path and the program displays the JavaFX panel as expected.
The system out is:
jdk.module.path : null
jdk.module.upgrade.path : null
jdk.module.main : null
jdk.module.main.class : null
When ran from an Eclipse launcher, I have to add to the launcher the following vm arguments:
--module-path=${env_var:JAVAFX_PATH} --add-modules=javafx.controls
and the panel is also displayed but the output is:
jdk.module.path : C:\dev\tools\javafx-sdk-11\lib
jdk.module.upgrade.path : null
jdk.module.main : null
jdk.module.main.class : null
jdk.module.main.class : null
I cannot make it work in Eclipse as it works from the command line: I am forced to mess with the modules and module-path. If I do not add the vm parameters, I got either "Error: JavaFX runtime components are missing, and are required to run this application" or "Error occurred during initialization of boot layer java.lang.module.FindException: Module javafx.controls not found".
How can it work form the command-line without any more configuration ? To my knowledge Maven do not add automagically anything to the module path...
Any idea ? What am I missing ?
Update1: I realized that when importing the project in Eclipse "as Maven project" (which is what I always do) it results in the JRE being added in the module path (which is not the case for my classis projects). See the screenshot
When running from command line, if you are choosing the Maven (same works for Gradle) build system, you let the plugins do the work for you.
When you run from your IDE the main class, but not from the built-in Maven/Gradle windows, on the contrary, you are running the plain java command line options.
And these results in two different things (but with same final result of course), as you already have figured out via the properties print out.
As already covered by this answer for IntelliJ, but applies to any other IDE, or this other one for Eclipse, there are two ways of running a JavaFX 11 project, based on the use or not of the Maven/Gradle build system.
JavaFX project, without build tools
To run your JavaFX project from your IDE, you have to download the JavaFX SDK and add a library with the different javafx jars to your IDE, with a path like /Users/<user>/Downloads/javafx-sdk-11/lib/.
Now, to run that project, even if it is not modular, you have to add the path to those modules, and include the modules you are using to the VM options/arguments of the project.
Whether you run the project from your IDE or from command line, you will be running something like:
java --module-path /Users/<user>/Downloads/javafx-sdk-11/lib/ \
--add-modules=javafx.controls org.openjfx.hellofx.HelloFX
Note that even if your project is not modular, you are still using the JavaFX modules, and since you are not using any build tool, you have to take care of downloading the SDK in the first place.
JavaFX project, build tools
If you use Maven or Gradle build tools, the first main difference is that you don't need to download the JavaFX SDK. You will include in your pom (or build.gradle file) what modules you need, and Maven/Gradle will manage to download just those modules (and dependencies) to your local .m2/.gradle repository.
When you run your main class from Maven exec:java goal you are using a plugin, and the same goes for the run task on Gradle.
At this point, it looks like when you run:
mvn compile exec:java
or
gradle run
you are not adding the above VM arguments, but the fact is that Maven/Gradle are taking care of it for you.
Gradle
In the Gradle case, this is more evident, since you have to set them in the run task:
run {
doFirst {
jvmArgs = [
'--module-path', classpath.asPath,
'--add-modules', 'javafx.controls'
]
}
}
While you don't need the SDK, the classpath contains the path to your .m2 or .gradle repository where the javafx artifacts have been downloaded.
Maven
For Maven, while the pom manages the dependencies of the different javafx modules, and sets the classifier to download the platform-specific modules (see for instance /Users/<User>/.m2/repository/org/openjfx/javafx-controls/11/javafx.controls-11.pom), the plugin manages to configure the classpath and create the required options to run the project.
In short, a new class that doesn't extend Application is used to call your application class: HelloFX.main(args).
EDIT
See this answer for a more detailed explanation on why launching a JavaFX application without module-path fails. But in short:
This error comes from sun.launcher.LauncherHelper in the java.base module. The reason for this is that the Main app extends Application and has a main method. If that is the case, the LauncherHelper will check for the javafx.graphics module to be present as a named module. If that module is not present, the launch is aborted.
A more detailed explanation on how the maven plugin works without setting the module-path:
If you add debug level (default is info) when running the Maven goals, you will get more detailed information on what is going on behind the scenes.
Running mvn compile exec:java shows:
...
[DEBUG] (f) mainClass = org.openjfx.hellofx.HelloFX
...
[DEBUG] Invoking : org.openjfx.hellofx.HelloFX.main()
...
And if you check the exec-maven-plugin source code, you can find at ExecJavaMojo::execute how the main method of the Application class is called from a thread.
This is exactly what allows launching an Application class from an external class that does not extend Application class, to skip the checks.
Conclusion
Is up to you to choose build tools or not, though nowadays using them is the preferred option, of course. Either way, the end result will be the same.
But it is important to understand what are the differences of those approaches, and how your IDE deals with them.

Categories

Resources