0

I want to load meta data from an MP3 file, to be played by a JavaFx MediaPlayer. This works fine in the unit test, but not in the application. In the unit test, 6 items of metaData reported, but zero in the application. The method that "does the work" is the same.

The main class of the application extends Application. The test class extends ApplicationTest from TestFx. Could that affect the behavior?

The application:

public class MediaMain extends Application {

    @Override
    public void start(Stage primaryStage) throws Exception {

        Map<String, Object> meta = metaData();

        System.out.printf("Number of meta data: %d.%n", meta.size());
        System.out.println(meta);
    }

    Map<String, Object> metaData() {
        File audioFile = new File("src/main/resources", "beingBoiled.mp3");
        final URI uri = audioFile.toURI();
        final String source = uri.toString();
        Media media = new Media(source);
        new MediaPlayer(media);
        return media.getMetadata();
    }
}

The unit test:

class MediaMainTest extends ApplicationTest {

    @Test
    void testMeta() {
        MediaMain main = new MediaMain();

        Map<String, Object> metaData = main.metaData();

        assertNotEquals(0, metaData.size());
        System.out.printf("Number of meta data: %d.%n", metaData.size());
        System.out.println(metaData);
    }
}

Printout from the application:

Number of meta data: 0.
{}

Printout from the unit test:

Number of meta data: 6.
{year=1980, artist=The Human League, raw metadata={ID3=java.nio.HeapByteBufferR[pos=254 lim=3214 cap=3214]}, album=Travelogue, genre=(52), title=Being Boiled}

What could be the reason? It's a mystery to me. Written with Java 11, JavaFx 11.0.2 and TestFx 4.0.15-alpha.

Helge
  • 145
  • 9
  • The metadata of a `Media` is lazily loaded, meaning it may not be available immediately. You can observe the metadata in order to be notified when certain attributes become known. – Slaw Oct 10 '19 at 20:58

1 Answers1

0

You are referencing a file with a location of src/main/resources, this is probably not a good idea as your deployed application likely won't have a src/main/resources directory, plus the resource might be bundled within the application jar rather than as a file on disk, so using a file protocol to access it won't work.

It is probably best to use something like below:

String mediaLoc = getClass().getResource("/beingBoiled.mp3").toExternalForm()
Media media = new Media(mediaLoc)

Like in How load css file in javafx8. The exact location of the resource to be loaded may differ based on build and project structure. If you don't want to load from the class path, but instead via a File or over network http call, then you would need to use something else.

The above code assumes that your build system is setup to copy the media from the src/main/resources to your target packaging location and package the resource into the application distributable (e.g. an application jar file) in the root of the jar file.

Make sure that your build system is actually copying the file to the target location. You can check if it is there by running your build, looking at the resultant jar and running jar tvf <myjarfilename>.jar to see if the mp3 resource is in the correct location at the root of the jar file.

jewelsea
  • 150,031
  • 14
  • 366
  • 406
  • In the end, I will not load the audio files form the resources folder, that's just a temporary solution. If I start the player in the tested method, the song will play in both the application and in the unit test. but the metadata will still be absent in the application. I''m running in the IDE of IntelliJ, latest community edition, on Mac and Windows. – Helge Oct 10 '19 at 19:59
  • The meta data is an ObservableMap, it's contents might change over time based upon the media loaded and the state of the media player. Try listening for change to the map and logging them. – jewelsea Oct 10 '19 at 20:15
  • When I'm running my tested method in the two contexts (the Main class and the MediaMainTest extends ApplicationTest class), I have tested with delays before the metaData is queried (didn't change anything), and also looked at the player status. It's different; in the MediaMain application, it's reported as UNKNOWN even after the player is started, whereas for the unit test it changes to READY or PLAYING, at least after a suitable delay. – Helge Oct 10 '19 at 21:35
  • I'm convinced that the difference lies in how the context is different between the class MediaMain extends Application, versus the unit test in class MediaMainTest extends ApplicationTest. But I don't understand how. – Helge Oct 10 '19 at 21:40
  • If you haven't already, please try what I suggested, [add a listener](https://openjfx.io/javadoc/13/javafx.base/javafx/collections/ObservableMap.html#addListener(javafx.collections.MapChangeListener)) to the ObservableMap of meta data and log its changes. Also, [source code in the media package Javadoc](https://openjfx.io/javadoc/13/javafx.media/javafx/scene/media/package-summary.html) includes comprehensive logging and exception reporting information for using Media. Please implement all of it and examine logs. – jewelsea Oct 10 '19 at 22:38
  • For an example of displaying metadata and using a change listener on it, see: ["Plays a list of Audio Files in JavaFX, displaying the media metadata of each file"](https://gist.github.com/jewelsea/1446612), which answers [Java Music Player: Song information and playing](https://stackoverflow.com/questions/17035762/java-music-player-song-information-and-playing). – jewelsea Oct 10 '19 at 22:45
  • Using a listener solves my actual application problem, allthough not the problem as described here (why the same method behaves differently in two use cases). Interesting for the MediaMain class, is that when I added a listener, it only was called after the start method exited. In my actual application, I want to update a text field in either a Swing or a JavaFx gui. That works now, so I'm satisfied. – Helge Oct 11 '19 at 11:51