)
Not a noob, but a noob question, as Java stuff has happened so long ago in my life, I really feel old now...
Error:
Exception in thread "main" java.lang.RuntimeException: java.lang.ClassNotFoundException: application.VideoPlayer
at javafx.graphics@19/javafx.application.Application.launch(Application.java:314)
at application.VideoPlayer.main(VideoPlayer.java:8)
Caused by: java.lang.ClassNotFoundException: application.VideoPlayer
at java.base/jdk.internal.loader.BuiltinClassLoader.loadClass(BuiltinClassLoader.java:641)
at java.base/jdk.internal.loader.ClassLoaders$AppClassLoader.loadClass(ClassLoaders.java:188)
at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:521)
at java.base/java.lang.Class.forName0(Native Method)
at java.base/java.lang.Class.forName(Class.java:495)
at java.base/java.lang.Class.forName(Class.java:474)
at javafx.graphics@19/javafx.application.Application.launch(Application.java:302)
at application.VideoPlayer.main(VideoPlayer.java:8)
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
at java.base/java.lang.reflect.Method.invoke(Method.java:578)
at jdk.compiler/com.sun.tools.javac.launcher.Main.execute(Main.java:434)
at jdk.compiler/com.sun.tools.javac.launcher.Main.run(Main.java:205)
at jdk.compiler/com.sun.tools.javac.launcher.Main.main(Main.java:132)
Code, VideoPlayer.java (javafx example code by some stackoverflow user)
package application;
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.web.WebView;
import javafx.stage.Stage;
public class VideoPlayer extends Application {
public static void main(String[] args) { launch(args); }
@Override public void start(Stage stage) throws Exception {
WebView webview = new WebView();
webview.getEngine().load(
"http://www.youtube.com/embed/utUPth77L_o?autoplay=1"
);
webview.setPrefSize(640, 390);
stage.setScene(new Scene(webview));
stage.show();
}
}
PATHs JAVA_HOME and PATH_TO_FX are set, bytecode generation completes without warning or error any kind: (I just added all modules I found in the fx directories to rule out something's amiss here...
javac --module-path $PATH_TO_FX --add-modules javafx.base,javafx.controls,javafx.fxml,javafx.graphics,javafx.media,javafx.swing,javafx.web VideoPlayer.java
Now when running the bytecode using
java --module-path $PATH_TO_FX --add-modules javafx.base,javafx.controls,javafx.fxml,javafx.graphics,javafx.media,javafx.swing,javafx.web VideoPlayer.java
the error at this whining's beginning occurs.
Please, I beg you, help me out as it's for sure something incredibly stupid and I'm not only feeling old now for the java stuff so many years in my past but also incredibly stupid.
Thank you, DaBird
PS: I tried to find whatever is missing there, regarding "application.VideoPlayer", nothing of value :-(
PPS: Linux Mint, Java SDK 19, OpenJavaFX from the project's download area, version 19
CodePudding user response:
Preface: If you're new to JavaFX development, or need a refresher, then I recommend reading Getting Started with JavaFX 11 .
Building & Running Project
There are a couple things that are "wrong" with your setup.
Your VideoPlayer
class is declared to be in the application
package. Yet from your javac
command, I gather your VideoPlayer.java
file is not under a directory named application
. In other words, your project structure should look something like the following:
<working-directory>
\---application
VideoPlayer.java
Then compile the project with:
javac -p <path-to-javafx> --add-modules javafx.web application/VideoPlayer.java
Note: You only need to add javafx.web
in your case, as it transitively requires javafx.base
, javafx.graphics
, and javafx.controls
. Your code isn't using any of the other JavaFX modules.
And then run it with:
java -p <path-to-javafx> --add-modules javafx.web application.VideoPlayer
Notice I used the fully-qualified name of the main class application.VideoPlayer
. This is the name of the class, not the name of the source file. You specified the source file in your question (which is part of where your error comes from).
Also, note that the project structure described above is not strictly necessary when compiling. It does, however, matter at run-time (at least with the default ClassLoader
implementations). See this other Q&A for more information. Though this is not where your error comes from, at least not directly.
All that said, I recommend using a build tool and/or an IDE when developing JavaFX applications. How to set these up is described in Getting Started with JavaFX 11 . But if you insist on compiling manually, then I recommend using the -d
option to set an output directory, as that will create the correct directory structure for the class files regardless of your source file structure.
Your Error
Note this section of my answer only exists to explain your error. If you follow the suggestions above and from Getting Started with JavaFX 11 then this error will no longer apply to you.
Your command to run your application looks like the following:
java -p <path-to-javafx> --add-modules javafx.web VideoPlayer.java
Here you're specifying the source file (VideoPlayer.java
). Prior to Java 11 this would have resulted in an error (there's no class named VideoPlayer.java
on the class-path). But you're using Java 11 , which means JEP 330: Launch Single-File Source-Code Programs comes into play. This lets you launch a single source file without having to compile it first. It does this internally by compiling the source file into memory. This involves using a separate class loader implementation than "normal", and this is where the error comes from.
You're calling launch(args)
. That is the Application#launch(String...)
method, which is essentially a convenience method for Application#launch(Class,String...)
for when the calling class is the application class you want to launch. In your case, the calling class is application.VideoPlayer
.
The problem is that Application#launch(String...)
uses the calling thread's context class loader to try and get a reference to the calling class's Class
. By default, that seems to be the system/application class loader (see documentation of built-in loaders). But that is not the class loader that loaded the application.VideoPlayer
class; that class was loaded by an in-memory class loader implementation. Therefore, the class cannot be found when JavaFX attempts to load it. This class loader issue is the reason why your stack trace says application.VideoPlayer
could not be found but still show that its main
method could be called successfully.
There are two ways to solve this if you're sticking with a single-source file execution.
public static void main(String[] args) {
// Option 1:
Thread.currentThread().setContextClassLoader(VideoPlayer.class.getClassLoader());
launch(args);
// Option 2:
launch(VideoPlayer.class, args);
}
Either approach will let the reflection code of JavaFX see your class.