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

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.

Related

Using commons-codec in a stand-alone JAR via Maven

I've been recently trying to create a simple CLI tool. My flow is as follows:
created the project with Maven from the default archetype
mvn archetype:generate -DgroupId=com.mycompany.app -DartifactId=my-app -DarchetypeArtifactId=maven-archetype-quickstart -DarchetypeVersion=1.4 -DinteractiveMode=false
I build the project with mvn clean install. This creates a targets folder, containing the .jar.
To run as java -jar ./someJar.jar {INPUT}, I've had to add a few things to pom.xml, e.g.,
<plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<descriptorRefs>
<descriptorRef>jar-with-dependencies</descriptorRef>
</descriptorRefs>
</configuration>
</plugin>
but this works fine, until I try to add an external library. For example, I've been trying to add murmur3 hashing capability via commons-codec, by adding
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.15</version>
</dependency>
to the pom.xml. Source using this is as simple as it gets:
package com.someRandomString.app;
import org.apache.commons.codec.digest.MurmurHash3;
public class hasherServiceOfSorts {
public static int murmur3_hash(final String data) {
return MurmurHash3.hash32(data);
}
}
and, upon invoking mvn clean install, actually builds fine. the issue is, when running the jar. It fails when invoking this method with
Exception in thread "main" java.lang.NoClassDefFoundError: org/apache/commons/codec/digest/MurmurHash3
indicating the origin commons-codec is not part of the baked JAR. My question is, what am I doing wrong/how does one force maven to include external JARs in the final package (if possible). I guess the alternative would be to run via java -cp some.jar some.class.app, which I'm trying to avoid (having a single "binary" is very attractive. Thanks!
As suggested by #Jesper, using https://maven.apache.org/plugins/maven-shade-plugin/ did the trick.

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();
}
}

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

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

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.

Why does Maven test not work after mvn clean unless I run mvn update?

I'm running some service testing using restassured and cucumber and they work fine locally just using Maven test.
The issue is if I run Maven clean, then I must run Maven update or it will not work (Says it can't find my Cucumber feature files). For reference it says:
No features found at [classpath:classpath/classpath]
This wouldn't be a huge issue except I need to have this running through Bamboo where I can't call Maven update.
So I either need to figure out what is wrong with my POM to begin with to cause this issue, or how I can run Maven update through the goals/environment variables.
The POM is fairly simple, only having the needed dependencies/reporting stuff.
The build part of the POM is as follows:
<build>
<finalName>Test</finalName>
<directory>target</directory>
<outputDirectory>target/classes</outputDirectory>
<testOutputDirectory>target/test-classes</testOutputDirectory>
<sourceDirectory>src/main/java</sourceDirectory>
<testSourceDirectory>src/test/java</testSourceDirectory>
<resources>
<resource>
<directory>src/test/resources</directory>
</resource>
</resources>
</build>
This is all in Java 8 using Eclipse as the IDE.
I would avoid specifying anything in the build section in my pom and instead use the default values.
That is, I would keep my feature files in the same package as the runner or a sub package.
The runner could for example live in the package se/thinkcode/tage
As in the directory:
./test/java/se/thinkcode/tage
This means that the feature files should live in the directory:
./test/resources/se/thinkcode/tage
This would allow me to minimize the configuration in the runner. I typically use runners that looks like this:
package se.thinkcode.tage;
import cucumber.api.junit.Cucumber;
import org.junit.runner.RunWith;
#RunWith(Cucumber.class)
public class RunCukesTest {
}
This is the smallest configuration possible if you want to run Cucumber using JUnit from Maven.
It is even smaller that the example supplied by the Cucumber team: https://github.com/cucumber/cucumber-java-skeleton
Looks like defining the features/glue in the cucumber options fixed this.
I do believe there is a better option though.
I added the following cucumber options:
features ="src/test/java",
glue = "packagename",

Categories

Resources