Resources
The Class#getResource(String)
and related API are used for locating resources relative to the class path and/or module path. When using Class
to get a resource you can pass an absolute name or a relative name. An absolute name will locate the resource relative to the root of the class path/module path; an absolute name starts with a /
. A relative name will locate the resource relative to the location of the Class
; a relative name does not start with a leading /
.
In a typical Maven/Gradle project structure, the src/main/java
and src/main/resources
are roots of the class path/module path. This means all resource names are relative to those directories. It's slightly more complicated than that because the files under those directories are moved to the target/build directory and it's that location that's put on the class path/module path, but for all intents and purposes consider the source directories as the root. There's a reason a get-resource API exists in the first place, to provide an application-location-independent way of obtaining resources.
Issues in Your Code
From your question I gather your project structure looks something like:
<project-dir>
|--src/
|--main/
|--java/
|--resources/
|--images/
|--image.png
And you're calling your method with an Object
and a resource name of image.png
. The problem here is that, since you're passing a relative name, the resource is located relative to the Class
of the passed Object
(i.e. context
). I doubt your class is located in a package named images
which means the resource will not be found relative to said class. You need to pass an absolute name: /images/image.png
.
The other problem is your use of URL#getPath()
. The URL
you obtain from Class#getResource(String)
will, if the resource were to be found, look something like this:
file:/path/to/gradle/project/build/resources/main/images/image.png
But the result of URL#getPath()
will give you:
/path/to/gradle/project/build/resources/main/images/image.png
This causes a problem due to the way Image
works. From the documentation:
All URLs supported by URL
can be passed to the constructor. If the passed string is not a valid URL, but a path instead, the Image is searched on the classpath in that case.
Notice the second sentence. If the passed URL does not have a scheme then it's interpreted as a resource name and the Image
will locate the image file relative to the classpath. In other words, since you're passing the value of URL#getPath()
to the Image
constructor it searches for the resource image.png
in the package path.to.gradle.project.build.resources.main.images
. That package does not exist. You should be passing the URL as-is to the Image
constructor via URL#toString()
or URL#toExternalForm()
.
Solution
If you're going to use the URL
returned by Class#getResource(String)
to load the Image
then no matter what you need to use URL#toString()
or URL#toExternalForm()
instead of URL#getPath()
.
public static Image createImage(Object context, String resourceName) {
URL _url = context.getClass().getResource(resourceName);
return new Image(_url.toExternalForm());
}
Then you have at least two options:
Pass the absolute resource name (i.e. "/images/image.png"
) to your #createImage(Object,String)
method since the image.png
resource is not in the same package as the passed Object
(i.e. context
).
Move the resource to the same package as the class of the passed in Object
(i.e. context
). For instance, if the context object's class is com.foo.MyObject
then place the resource under src/main/resources/com/foo
and it will be in the same package as MyObject
. This will allow you to continue passing the relative resource name.
Of course, as noted by the documentation of Image
you can pass a scheme-less URL and it's interpreted as a resource name. In other words, you could do:
Image image = new Image("images/image.png");
And that should work. A note of caution, however: When using modules the above will only work if the resource-containing package is opens
unconditionally or if the module itself is open
.