Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

intelliJ IDEA add resources to JAR

I got an application which is working with resources (.wav .png- files). I want to include those resources in my .jar, when I build my project.

Running the application from the IDE works well.

As described here, I created the resources-folder at the same level of my src-folder

My project-structure:

ProjectName --        
              |
              out
              |
              resources --
              |           |
              |           sounds
              |           |
              |           images
              src --
                    |
                    ...

As described here, I have marked the folder resources as Resources root.

As described here, I created my own artifacts in the Project structure. Thats how they look like: enter image description here

The piece of code, that works with an audio file for example:

new Media(new File("resources/sounds/login_sound.wav").toURI().toString());

When I try to run the jar via terminal, Iam getting the following error:

Caused by: MediaException: MEDIA_UNAVAILABLE : /home/moritz/IdeaProjects/TheFloorIsLavaGUI/out/artifacts/TheFloorIsLavaGUI_jar/resources/sounds/login_sound.wav (File or directory not found)

The full stack-trace:

    moritz@Momix:~/IdeaProjects/TheFloorIsLavaGUI/out/artifacts/TheFloorIsLavaGUI_jar$ java -jar TheFloorIsLavaGUI.jar 
Gtk-Message: 12:33:12.649: Failed to load module "canberra-gtk-module"
Exception in Application start method
java.lang.reflect.InvocationTargetException
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at com.sun.javafx.application.LauncherImpl.launchApplicationWithArgs(LauncherImpl.java:389)
    at com.sun.javafx.application.LauncherImpl.launchApplication(LauncherImpl.java:328)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at sun.launcher.LauncherHelper$FXHelper.main(LauncherHelper.java:767)
Caused by: java.lang.RuntimeException: Exception in Application start method
    at com.sun.javafx.application.LauncherImpl.launchApplication1(LauncherImpl.java:917)
    at com.sun.javafx.application.LauncherImpl.lambda$launchApplication$154(LauncherImpl.java:182)
    at java.lang.Thread.run(Thread.java:748)
Caused by: MediaException: MEDIA_UNAVAILABLE : /home/moritz/IdeaProjects/TheFloorIsLavaGUI/out/artifacts/TheFloorIsLavaGUI_jar/resources/sounds/login_sound.wav (Datei oder Verzeichnis nicht gefunden)
    at javafx.scene.media.Media.<init>(Media.java:407)
    at managers.SoundManager.playSong(SoundManager.java:71)
    at main.TheFloorIsLavaGUI.start(TheFloorIsLavaGUI.java:39)
    at com.sun.javafx.application.LauncherImpl.lambda$launchApplication1$161(LauncherImpl.java:863)
    at com.sun.javafx.application.PlatformImpl.lambda$runAndWait$174(PlatformImpl.java:326)
    at com.sun.javafx.application.PlatformImpl.lambda$null$172(PlatformImpl.java:295)
    at java.security.AccessController.doPrivileged(Native Method)
    at com.sun.javafx.application.PlatformImpl.lambda$runLater$173(PlatformImpl.java:294)
    at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
    at com.sun.glass.ui.gtk.GtkApplication._runLoop(Native Method)
    at com.sun.glass.ui.gtk.GtkApplication.lambda$null$48(GtkApplication.java:139)
    ... 1 more
Exception running application main.TheFloorIsLavaGUI

Any advices? Thank you

like image 477
Moritz Schmidt Avatar asked Jun 08 '18 10:06

Moritz Schmidt


1 Answers

TL;DR:

Load the file from the classpath instead of from the filesystem:

new Media(
  Test.class.getResource(
    "resources/sounds/login_sound.wav"
   ).toURI().toString())`

Explanation: there are a couple of things going on here:

  • You are trying to load a file from a path /your/home/.../project/out/artifacts/.../resources/.... By marking resources as a resource folder, you tell IntelliJ to put all files there in the root of the classpath, as shown in the screenshot.

enter image description here

  • It does not put that file in the file system but includes it in the jar

  • When running from the IDE, new File("resources/sounds/login_sound.wav").toURI() evaluates to /home/moritz/IdeaProjects/TheFloorIsLavaGUI/resources/sounds/login_sound.wav which is the location of the file in your project. When running from the jar, it evaluates to the path in the output folder, /home/moritz/IdeaProjects/TheFloorIsLavaGUI/out/artifacts/TheFloorIsLavaGUI_jar/resources/sounds/login_sound.wav, which is not the location the build puts it to.

Now, the correct way of dealing with this is to load the resources not from the file system but from the classpath. Try running the following from the IDE and from the jar to see the difference

System.out.println(new File("foo.wav").toURI().toString());
System.out.println( Test.class.getResource("foo.wav").toURI().toString());

// From IDE
file:/Users/.../untitled/foo.wav
file:/ Users/.../untitled/out/production/untitled/foo.wav

// From Jar
file:/Users/.../untitled/out/artifacts/foo.wav
jar:file: /Users/.../untitled/out/artifacts/untitled_jar/untitled.jar!/foo.wav

Note that Media accepts jar URIs: https://docs.oracle.com/javafx/2/api/javafx/scene/media/Media.html#Media%28java.lang.String%29

So what you need to to is actually simple. Change loading the wav from new Media(new File("resources/sounds/login_sound.wav").toURI().toString()); to new Media(Test.class.getResource("resources/sounds/login_sound.wav").toURI().toString())

Besides that: You might want to look into build tools like gradle or maven and not build from the IDE.

like image 123
wwerner Avatar answered Oct 04 '22 02:10

wwerner