File loads in eclipse but not in a runnable .jar [solved]

I have a game completely done, but I need to make a runnable jar of it. I have a res folder with subfolders that contain textures and sounds and midi music.
The images and sounds load perfectly, but the midi files, while they play when I run the game in eclipse, they do not run when I play the game as a runnable jar.

The problem is with the file loading. I checked and the game is throwing an IOException when I try to load the file.

I do not have this problem with other resources. Can anyone help me out here? I need to get the game runnable in the next few hours.

Thanks

Is the MIDI loader made by yourself or is it some other library?

I got it from someone else. Here it is:


import java.io.File;
import java.io.IOException;

import javax.sound.midi.*;

public class MusicPlayer {

    public static Song currentSong;
    private static Sequencer midiPlayer;

    //i know it's kinda stupid to have an enum for just this purpose but it makes some other code just slightly easier so cut me a break :p
    public static enum Song{
		MENU("menu"),
		LEVEL_1("level_1"),
		LEVEL_2("level_2"),
		LEVEL_3("level_3"),
		LEVEL_4("level_4"),
		LEVEL_5("level_5"),
		LEVEL_6("level_6"),
		LEVEL_7("level_7"),
		LEVEL_8("level_8"),
		LEVEL_9("level_9"),
		LEVEL_10("level_10"),
		ENDING("ending");
		
    	public String name;
    	
		Song(String n){
    		name = n;
    	}
    }
    
	public static void playMidi(Song song){
		try {
			midiPlayer = MidiSystem.getSequencer();
			midiPlayer.setSequence(MidiSystem.getSequence(new File("res/music/"+song.name+".mid")));
			midiPlayer.open();
			midiPlayer.setLoopCount(Sequencer.LOOP_CONTINUOUSLY);
			midiPlayer.start();
			currentSong = song;
        } catch (MidiUnavailableException ex) {
        	System.err.println("Midi Unavailable! "+ex.toString());
        } catch (InvalidMidiDataException ex) {
        	System.err.println("Midi Invalid! "+ex.toString());
        } catch (IOException ex) {
        	System.err.println("File Not Found! "+ex.toString());
        	//i hear this rejection sound in the runnable jar, but the music plays perfectly in eclipse
        	Sound.shotFail.play();
        }
    }
	
	public static void stop(){
		if(midiPlayer != null){
			if(midiPlayer.isOpen()){
				midiPlayer.stop();
				midiPlayer.close();
			}
		}
	}
}

Well, it looks right, unless the file extension is wrong or unless you actually set the path wrong. Make some sort of debug message to print out what the filename is.

I highly doubt the path is wrong. Like I said, this works in eclipse and I use a practically similar method to load the PNGs that work perfectly in the JAR. I think it’s something with the midi, but I couldn’t imagine what.

Oh, I also used to experience problems between using //, /, and \ for file paths. Might want to try those alternatives. :open_mouth:

It depends where the midi is.

If the midi is within your jar, you might want to try loading it like this…


File newFile = null;
URL tempURL = Thread.currentThread().getContextClassLoader().getResource(filename);
if(tempURL != null){
    try {
                newFile = new File(tempURL.toURI());
    } catch (URISyntaxException ex) {
            	System.err.println("File Resource Error! "+filename);
    }
}

or, you can also put a copy of the midi in that path in a zip with your jar. It’ll look like this in the file system.


(yourgame).zip contents
-----------
(yourgame).jar
res(folder) -> music(folder) -> (songname).mid

That should solve your problem…

Sorry to be such a pain, but is there something I’m missing here? I can’t get Thread.currentThread().getContextClassLoader().getResource() to work for any resource, including resources that I know are there for a fact. The code doesn’t work in eclipse or in a Jar. Is there some special common setup that is necessary for this to function that I don’t have implemented?

Just a note, I tested it and “Thread.currentThread().getContextClassLoader()” does return an object, so the problem is only with the getResource() method

Thanks


midiPlayer.setSequence(MidiSystem.getSequence(getClass().getResourceAsStream("/res/music/"+song.name+".mid")));

The res folder needs to be placed at the root of your package tree (Typically the root of the jar).

There is another way to get files from a .jar…


File newFile = null;
URL tempURL = getClass().getResource("/"+filename);
if(tempURL != null){
      try {
                newFile = new File(tempURL.toURI());
      } catch (URISyntaxException ex) {
            	System.err.println("File Resource Error! "+filename);
      }
}

EDIT: ninja’d…

Shouldn’t the “getClass()” method be called from an object? How is it just floating there?

“Cannot make a static reference to the non-static method getClass() from the type Object”
?

EDIT: OOOH Because I’m calling the method statically… hmm…

Hrmm… even when I call this method non-statically it doesn’t work. I’m not gonna lie, I have no idea what any of this is or why it isn’t working.

public void playMidi1(Song song){
		String filename = "res/music/"+song.name+".mid";
		File newFile = null;
		URL tempURL = getClass().getResource(filename);
		if(tempURL != null){
		      try {
		                newFile = new File(tempURL.toURI());
		      } catch (URISyntaxException ex) {
		               System.err.println("File Resource Error! "+filename);
		      }
		}
		
		try {
			midiPlayer = MidiSystem.getSequencer();
			midiPlayer.setSequence(MidiSystem.getSequence(newFile));
			midiPlayer.open();
			midiPlayer.setLoopCount(Sequencer.LOOP_CONTINUOUSLY);
			midiPlayer.start();
			
			currentSong = song;
        } catch (MidiUnavailableException ex) {
        	System.err.println("Midi Unavailable! "+ex.toString());
        } catch (InvalidMidiDataException ex) {
        	System.err.println("Midi Invalid! "+ex.toString());
        } catch (IOException ex) {
        	System.err.println("File Not Found! "+ex.toString());
        	Sound.shotFail.play();
        }
	}

I’m not butchering the order of code or anything, am I? The resource is always null

Try this


URL tempURL = getClass().getClassLoader().getResource(filename);

instead of


URL tempURL = getClass().getResource(filename);

Err… didn’t work. Somebody commented about saving it in the root of the project? I’m not sure what this means and I wasn’t able to figure it out with google, probably because I wasn’t using the right key words. Is this music folder in the root?

This might not help at all, as you said the images loaded fine, just not the midis; but…

Did you add your res folder as a class folder? (java build path, libraries, add class folder)

Did you tell eclipse to export your res folder to the jar? (java build path, order and export, check res folder)

Finally did you tell eclipse to bundle libraries with your jar when it generated it? If not users would need your jar file, plus a resources folder in the same directory.

Like I said, might not help (or you already did these) just didn’t want something simple to be overlooked on accident.

Instead of using a folder, make it a package and add drag the resources into the package and delete the folder. Like in this image.

I’ve done all of those, except for the class folder. But when I do that, I get this:

So I’m not sure that’s the problem

Make it like in the image i’ve shown. Then the class loader loads it well. Dont use class folders.

I cannot make it like the image you’ve shown, I can’t put a package in a package. Maybe my version of eclipse is just old.

However, when I do this:

and make the filename this:

		String filename = "src/music/"+song.name+".mid";

It still says the URL is null

Just click the src folder and create a package with name res.