Search code examples
javaintellij-plugin

How to use relative path instead of absolute


So I need to set an icon for Intellij IDEA plugin, but when I'm trying to get this icon from my project with new File(relative path) or getClass().getResource(relative path). It can't find the files, only works with the absolute path. I have tried with the following relative paths:

  1. images/icon.png
  2. resources/images/icon.png
  3. main/resources/images/icon.png
  4. src/main/resources/images/icon.png

Icons path: src/main/resources/images/icon.png

Source code path: src/main/java/com/timetrack/plugin/MyClass.java

code:

File file = new File("src/main/resources/images/running.png");
BufferedImage img = ImageIO.read(file);

or with this

BufferedImage img = ImageIO.read(getClass().getResource("images/running.png"));

EDIT

Need to mention that I'am using Gradle to build the project. So the output directory looks like this:

Icon path: build/resources/main/images/icon.png

Compiled classes: build/classes/java/main/com/timetrack/plugin/MyClass.class


Solution

  • Your resource string needs to start with a slash, since it is not in the same package as your class.

    Paraphrased from the documentation of getResource:

    • If the name begins with a /, then the absolute name of the resource is the portion of the name following the /.
    • Otherwise, the absolute name is of the form modified_package_name/name, where the modified_package_name is the package name of this class with / substituted for ..

    In other words, the argument passed to Class.getResource is assumed to be in the same package as the Class itself, unless the argument starts with a slash.

    This is because the proper way to include resources in an application or library is to place them in the same package directory as the class that uses them. The reason for doing this is the same reason we use packages. For that matter, it’s the same reason applications don’t store all their files in the user’s home directory or in C:\: because there is a real risk that other programs will choose the same name and will interfere with your program.

    Class.getResource searches the classpath for the requested resource. If you package your icon as images/running.png, and a library also decides to package its image as images/running.png, then Class.getResource will search the classpath and return whatever it finds first. Depending on the order of the classpath entries, either you will get the wrong image, or that other library will. The two are essentially stepping on each other.

    On the other hand, if you place your image at src/main/resources/com/timetrack/plugin/running.png, it’s unlikely any other code will be using that package, so your odds of a collision are mimimal. And because this was intended to be the most common use case, using it this way is easier: You can retrieve the image URL with just MyClass.class.getResource("running.png").