How to Use Classloader.Getresources() Correctly

How to use ClassLoader.getResources() correctly?

There is no way to recursively search through the classpath. You need to know the Full pathname of a resource to be able to retrieve it in this way. The resource may be in a directory in the file system or in a jar file so it is not as simple as performing a directory listing of "the classpath". You will need to provide the full path of the resource e.g. '/com/mypath/bla.xml'.

For your second question, getResource will return the first resource that matches the given resource name. The order that the class path is searched is given in the javadoc for getResource.

ClassLoader.getResource returns odd path (maybe)?

  1. "the most common approach" is not necessarily the best :)
  2. Take care which path you mean: ClassLoader.getResource() returns a URL, which can have a path component. However, this is not necessarily a valid file-path.

    Note, that there is also a method Paths.get(URI) which takes a URI as parameter
  3. The first slash in /D:/Projects/myapp/build/resources/main/file.txt just means, that this is an absolute path: see Class.getResource
  4. I recommend, that you simply use ClassLoader.html#getResourceAsStream when you want to read a file

Update to answer comment: "So why does Paths.get() not accept the absolute path?"

Paths.get() does accept absolute paths.

But you must pass a valid (file-)path - and in your case you pass the URL-path directly (which is not a valid file-path).

  • When you call: getClass().getClassLoader().getResource("file.txt") it returns a URL: file:/D:/Projects/myapp/build/resources/main/file.txt
    • this URL consists of the schema file:
    • and the valid (absolute URL)path: /D:/Projects/myapp/build/resources/main/file.txt
  • you try to use this URL-path directly as a file-path, which is wrong
    • thus the Paths.get(String,..) method throws an InvalidPathException

To convert the URL path to a valid file-path you could use the Paths.get(URI) method like so:

URL fileUrl = getClass().getClassLoader().getResource("file.txt");
Path filePath = Paths.get(fileUrl.toURI());
// now you have a valid file-path: D:/Projects/myapp/build/resources/main/file.txt

Strange behavior of Class.getResource() and ClassLoader.getResource() in executable jar

I thought this question was already asked and answered!

  • What is the difference between Class.getResource() and
    ClassLoader.getResource()?

getClass().getResource() searches relative to the .class file while
getClass().getClassLoader().getResource() searches relative to the
classpath root.

If there's an SSCCE here, I don't understand why it doesn't

1) Show the directory organization in the .jar, and...

2) Take package into consideration

Q: What (if anything) hasn't already been answered by What is the difference between Class.getResource() and ClassLoader.getResource()? (and the links it cites)?

=========================================================================

I'm still not sure what isn't clear, but this example might help:

/*
SAMPLE OUTPUT:
ClassLoader.getResource(/subdir/readme.txt): NULL
Class.getResource(/subdir/readme.txt): SUCCESS

ClassLoader.getResource(subdir/readme.txt): SUCCESS
Class.getResource(subdir/readme.txt): NULL
*/
package com.so.resourcetest;

import java.net.URL;

public class ResourceTest {

public static void main(String[] args) {
ResourceTest app = new ResourceTest ();
}

public ResourceTest () {
doClassLoaderGetResource ("/subdir/readme.txt");
doClassGetResource ("/subdir/readme.txt");
doClassLoaderGetResource ("subdir/readme.txt");
doClassGetResource ("subdir/readme.txt");
}

private void doClassLoaderGetResource (String sPath) {
URL url = getClass().getClassLoader().getResource(sPath);
if (url == null)
System.out.println("ClassLoader.getResource(" + sPath + "): NULL");
else
System.out.println("ClassLoader.getResource(" + sPath + "): SUCCESS");
}

private void doClassGetResource (String sPath) {
URL url = getClass().getResource(sPath);
if (url == null)
System.out.println("Class.getResource(" + sPath + "): NULL");
else
System.out.println("Class.getResource(" + sPath + "): SUCCESS");
}
}

Here's the corresponding directory tree. It happens to be an Eclipse project, but the directories are the same regardless if it's Eclipse, Netbeans ... or a .jar file:

C:.
├───.settings
├───bin
│ ├───com
│ │ └───so
│ │ └───resourcetest
│ └───subdir
└───src
├───com
│ └───so
│ └───resourcetest
└───subdir

The file being opened is "subdir/readme.txt"


ADDENDUM 11/9/12:

Hi -

I copied your code verbatim from github, re-compiled and re-ran:

ClassLoader.getResource(/subdir/readme.txt): NULL
Class.getResource(/subdir/readme.txt): SUCCESS
ClassLoader.getResource(subdir/readme.txt): SUCCESS
Class.getResource(subdir/readme.txt): NULL

If that's not the output you're getting ... I'm baffled.

For whatever it's worth, I'm running:

  • Eclipse Indigo (it shouldn't matter)

  • Running inside the IDE (it shouldn't matter if it's filesystem or .jar, inside or outside an IDE)

  • My JRE is 1.6 (if anything, this is probably the biggie)

Sorry we haven't been able to resolve what I thought was a straightforward issue :(


ADDENDUM 11/21/12 (Andreas):

Since there was no recent activity on this question, I would like to summarize what we found:

  • From our common understanding, the answer to the above question is: "No, it is not possible that Class.getResource("/path/image.png") returns a valid URL, while ClassLoader.getResource("path/image.png") returns null":

    • We're completely clear on the difference between ClassLoader.getResource() and Class.getResource()
    • Our sample outputs match, for both "SUCCESS" and for "null"
    • The sample outputs match what we'd expect
    • Conclusion: Either we oversaw something, or something different caused the "solution" described in the linked question to work. I think we can not currently prove one or the other.

ClassLoader.getResource returning null while using File.getAbsolutePath

That's not the way to load resources via class-loaders.

If your classpath is something like the following ...

java -cp resources;lib/my.jar ... org.mypack.MyClass

then you load it with this path

getClassLoader().getResource("/config/config.ini");

Your classpath includes the resources folder, and the class-loader loads from there.

The absolute path of the OS is quite certainly not in classpath.

In any case, you must be certain that the resource folder is in classpath.

If your config file is not in classpath then you can't use classloaders to load that file.

Just one more thing, if your configuration is not in classpath, but in a child directory of your working dir, why can't you simply use new FileInputStream("resources/config/config.ini");

Custom classloader trouble with getResources for names ENDING in slash

Given all constraints this does not appear entirely possible in a rock solid fashion as I wanted it:

a) Third party libraries may always "misbehave" and get hold of lassloaders they are not supposed to use one way or another. I looked at OneJar as suggested by fge but they have the same issue - they only detect a possibility of it.

b) There is no way to completely replace/hide the system class loader.

c) Casting the system class loader to a URLClassLoader may stop working at any moment.

How should I use getResource() in Java?

String clipName = "Chook.wav";

When using getResource, the string you pass in must be either an absolute name or be valid relative to a certain class. Since you're using ClassLoader.getResource() and not Class.getResource(), it must be an absolute path.

Without seeing your actual file hierarchy, I can only guess that "bin" is the root of your compiled classes and resources, and "ibm1260" is a package/folder within that path, and "Chook.wav" exists in that folder. If that's the case, then you need to use /ibm1260/Chook.wav (or potentially ibm1260/Chook.wav, I don't typically use the class loader for resource lookups) as the name of the file that you pass in to getResource().

Either way, you need to make sure that the file is copied into the location of your compiled code and that the root folder is on the classpath.

Java ClassLoader getResource with special characters in path

To answer my own question with the help of the comments:

URL resource = ClassLoader.getSystemResource("application.conf");
String configPath = URLDecoder.decode(resource.getFile(), "UTF-8");

Variable configPath then contains the correct path.



Related Topics



Leave a reply



Submit