Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to access a resource in Java project using Gradle?

I have a javafx project I'm building using a Gradle file, and I'm writing everything in Intellij. In it, I use javafx.scene.media.Media and javafx.scene.media.MediaPlayer to play some music.

public SoundPlayer(String filename) {
    String soundLocation = "\\src\\main\\resources\\sound\\" + fileName;
    String absolute = new File("").getAbsolutePath() + soundLocation;
    System.out.println(absolute);
    Media soundMedia = new Media(new File(absolute).toURI().toString());
    mediaPlayer = new MediaPlayer(soundMedia);
}

The project directory I had been working out of was:

src/

|---main/

|---|---java/

|---|---|---sound.SoundPlayer

|---|---resources/

|---|---|---sound/

|---|---|---|---click.mp3

|---|---|---|---bgm.mp3

however, when I went to compile and turn it into a jar file, Gradle changed the directory into this (within the jar file, top level):

sound/

|---SoundPlayer.class

|---click.mp3

|---bgm.mp3

That made it throw a Media Exception: MEDIA UNAVAILABLE. I've tried changing the file to both of the following:

Media soundMedia = new Media(new File("sound\\" + fileName).toURI().toString());

and

Media soundMedia = new Media(new File(fileName).toURI().toString());

... but I always get the same exception. What's going on?

like image 390
Will Rosser Avatar asked Oct 23 '15 20:10

Will Rosser


People also ask

What is resources folder in Gradle?

The resource directory is used mainly for storing files that were created before runtime, so that they can be accessed during runtime. It is not meant to be written to during runtime.

What is Java library in Gradle?

A library is a Java component meant to be consumed by other components. It's a very common use case in multi-project builds, but also as soon as you have external dependencies. The plugin exposes two configurations that can be used to declare dependencies: api and implementation .

Does Gradle support Java modules?

Building, testing and running Java Modules With this release, Gradle supports the Java Module System with everything you need to compile and execute tests for Java modules. You can also build Javadoc and run applications.


1 Answers

What Gradle did is completely expected. The src/main/java and src/main/resources directories store code and resources respectively. The resources folder contains all the non-java code like images,sound etc.

When creating the jar file, the contents of the resources directory will be copied as is (maintaining the package structure). Note that click.mp3 and bgm.mp3 are members of the sound package.

So, when you want to load a resource, it should (generally) not be done using file paths. Instead use, package structure to do so. Here, as the sounds and SoundPlayer have the same package, i.e. sound, you can use the SoundPlayer class to load resources like following:

public SoundPlayer(String filename) {
    URL resource = SoundPlayer.class.getResource(filename);
    Media soundMedia = new Media(resource.toExternalForm());
    mediaPlayer = new MediaPlayer(soundMedia);
}

From Javadocs

public String toExternalForm()
Constructs a string representation of this URL. The string is created by calling the toExternalForm method of the stream protocol handler for this object.

In essence, the toExternalForm() function creates the appropriate URL for a given resource.

Here is a complete example.

// build.gradle
apply plugin: 'java'
apply plugin: 'application'

sourceCompatibility = '1.8'
[compileJava, compileTestJava]*.options*.encoding = 'UTF-8'


mainClassName = 'sound.Main'

repositories {
    mavenCentral()
}

dependencies {
    testCompile group: 'junit', name: 'junit', version: '4.10'
}

jar { manifest { attributes 'Main-Class': 'sound.Main' } } 

and the modified SoundPlayer

//sound.SoundPlayer
package sound;

import java.net.URL;
import javafx.scene.media.Media;
import javafx.scene.media.MediaPlayer;

public class SoundPlayer {

    private MediaPlayer mediaPlayer;

    public SoundPlayer(String filename) {
        URL resource = SoundPlayer.class.getResource(filename);
        Media soundMedia = new Media(resource.toExternalForm());
        mediaPlayer = new MediaPlayer(soundMedia);
    }

    public void play(){
        mediaPlayer.play();
    }
}

and the Main class to use SoundPlayer

// sound.Main
// This class does not actually create a JavaFX UI. Instead, it is
// only creating a JavaFX application to use Media
package sound;

import javafx.application.Application;
import javafx.stage.Stage;

/**
 *
 * @author aga53
 */
public class Main extends Application{

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage primaryStage) throws Exception {
        SoundPlayer s = new SoundPlayer("test.mp3");
        System.out.println("Hello World");
        s.play();
    }

}
like image 188
Ankit Avatar answered Sep 18 '22 06:09

Ankit