How to reference a resource file correctly for JAR and Debugging?

JavaEclipseJar

Java Problem Overview


I have a nasty problem referencing resources when using a Maven project and Jar files...

I have all my resources in a dedicated folder /src/main/resources which is part of the build path in Eclipse. Files are referenced using

getClass().getResource("/filename.txt")

This works fine in Eclipse but fails in the Jar file - there the resources are located in a folder directly below the jar's root...

Does anyone know a 'best practice' to reference a file both in the JAR and (!) in Eclipse?

Edit: The problem is that while the resources actually are located in the JAR in a folder "resources" at the top level, the above method fails to find the file...

Java Solutions


Solution 1 - Java

Once you pack the JAR, your resource files are not files any more, but stream, so getResource will not work!

Use getResourceAsStream.

To get the "file" content, use https://commons.apache.org/proper/commons-io/javadocs/api-release/org/apache/commons/io/IOUtils.html:

static public String getFile(String fileName)
{
        //Get file from resources folder
        ClassLoader classLoader = (new A_CLASS()).getClass().getClassLoader();

        InputStream stream = classLoader.getResourceAsStream(fileName);

        try
        {
            if (stream == null)
            {
                throw new Exception("Cannot find file " + fileName);
            }

            return IOUtils.toString(stream);
        }
        catch (Exception e) {
            e.printStackTrace();

            System.exit(1);
        }

        return null;
}

Solution 2 - Java

I had a similar problem. After a full day of trying every combination and debugging I tried getClass().getResourceAsStream("resources/filename.txt") and got it to work finally. Nothing else helped.

Solution 3 - Java

The contents of Maven resource folders are copied to target/classes and from there to the root of the resulting Jar file. That is the expected behaviour.

What I don't understand is what the problem is in your scenario. Referencing a Resource through getClass().getResource("/filename.txt") starts at the root of the classpath, whether that (or an element of it) is target/classes or the JAR's root. The only possible error I see is that you are using the wrong ClassLoader.

Make sure that the class that uses the resource is in the same artifact (JAR) as the resource and do ThatClass.class.getResource("/path/with/slash") or ThatClass.class.getClassLoader().getResource("path/without/slash").

But apart from that: if it isn't working, you are probably doing something wrong somewhere in the build process. Can you verify that the resource is in the JAR?

Solution 4 - Java

If you add the resources directory in the jar file (so it is under the /resources folder in the jar, and if /src/main is in your build path in eclipse, then you should be able to reference your file as:

getClass().getResource("/resources/filename.txt");  

Which should work in both environments.

Solution 5 - Java

The problem is that within the IDE the getClass().getResource("Path"); String is not CASE SENSITIVE when accessing a file but when running from a jar it is. Check your Capitalisation on directory compared to file. It does work. Also if you try new File(getClass().getResource("Path"); the file won't be readable outside IDE.

Solution 6 - Java

Maybe this method can help for some situations.

public static File getResourceFile(String relativePath)
{
	File file = null;
	URL location = <Class>.class.getProtectionDomain().getCodeSource().getLocation();
	String codeLocation = location.toString();
	try{
		if (codeLocation.endsWith(".jar"){
			//Call from jar
			Path path = Paths.get(location.toURI()).resolve("../classes/" + relativePath).normalize();
			file = path.toFile();
		}else{
			//Call from IDE
			file = new File(<Class>.class.getClassLoader().getResource(relativePath).getPath());
		}
	}catch(URISyntaxException ex){
		ex.printStackTrace();
	}
	return file;
}

Solution 7 - Java

Just copy the file to a temporary directory.

String tempDir = System.getProperty("java.io.tmpdir");
File file = new File(tempDir.getAbsolutePath(), "filename.txt");
if (!file.exists()) {
     InputStream is = (getClass().getResourceAsStream("/filename.txt"));
     Files.copy(is, file.getAbsoluteFile().toPath());
}

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionPatrickView Question on Stackoverflow
Solution 1 - JavaThomas DecauxView Answer on Stackoverflow
Solution 2 - JavaandjelkoView Answer on Stackoverflow
Solution 3 - JavaSean Patrick FloydView Answer on Stackoverflow
Solution 4 - JavaSteven MastandreaView Answer on Stackoverflow
Solution 5 - JavaChristo NaudéView Answer on Stackoverflow
Solution 6 - JavagbiiView Answer on Stackoverflow
Solution 7 - JavaJuangui JordánView Answer on Stackoverflow