So I have a maven project in intellij and I want to load images from the resources folder. It works perfectly for files that are directly in resources/. However, files that are in subfolder (for example resources/images/) are not found.
In this example, logo.png is correctly loaded while logo1.png is not found :
var img2 = new Image("logo1.png"); var img = new Image("images/logo.png");
I could put all my files directly in resources, but it would be all disorganized…
Here’s the error I get when loading images/logo.png :
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:564) 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:564) 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:832) Caused by: java.lang.IllegalArgumentException: Invalid URL: Invalid URL or resource not found at javafx.graphics/javafx.scene.image.Image.validateUrl(Image.java:1125) at javafx.graphics/javafx.scene.image.Image.<init>(Image.java:618) at org.example/org.example.App.start(App.java:25) 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(AccessController.java:391) 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.gtk.GtkApplication._runLoop(Native Method) at javafx.graphics/com.sun.glass.ui.gtk.GtkApplication.lambda$runLoop$11(GtkApplication.java:277) ... 1 more Caused by: java.lang.IllegalArgumentException: Invalid URL or resource not found at javafx.graphics/javafx.scene.image.Image.validateUrl(Image.java:1117) ... 11 more Exception running application org.example.App Process finished with exit code 1
Advertisement
Answer
var img2 = new Image("logo1.png");
This code is just wrong, that’s not how you load resources.
This is how you do it:
var img2 = new Image(TheClassThisCodeIsIn.class.getResource("logo1.png").toString());
The new Image(string)
constructor takes as argument a URL, and logo1.png
is not one of those.
In particular you are looking to load images from the exact same place java is loading your app’s class files, which is done with someClassInstanceThatIsUsedForContext.getResource
. The best context to use is no doubt the class you’re in, hence, TheClassYouAreIn.class
, which gets you that class instance. The getResource
method returns a URL.
Note that the above construct is using relative paths: That code will look for a resource named logo1.png
in the same place that TheClassThisCodeIsIn.class
is located, even if it is in a jar file, dynamically created, or loaded over the network. In other words, if you have:
package com.foo.sashimisAwesomeApp; public class MyApp {}
Then MyApp.class.getResource("hello.png")
will look for com/foo/sashimisAwesomeApp/hello.png
, because the class file for MyApp
is at com/foo/sashimisAwesomeApp/MyApp.class
. This means you need to match the package structure (That com/foo/sashimisAwesomeApp
part) in your resource
folder in your project directory structure. If you prefer to go from the ‘root’ of resources, include a leading slash: MyApp.class.getResource("/images/icon.png")
will look in /images/icon.png
in the jar file that also contains /com/foo/sashimisAwesomeApp/MyApp.class
.
NB: Sidenote to the author of javafx’s Image class: Geez, what a disaster. That API should obviously have taken in a URL or URI or have a static constructor to load off of classpath instead of this mess.