Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

I understand from What is the difference between Class.getResource() and ClassLoader.getResource()? and from own code, that

getClass().getResource("/path/image.png") 

is identical to

getClass().getClassLoader().getResource("path/image.png") 

The posting Cannot read an image in jar file shows an issue where using

getClass().getClassLoader().getResource("path/image.png") 

in an executable jar file returns null, while

getClass().getResource("/path/image.png") 

returns the correct URL.

Since Class.getResource() delegates to ClassLoader.getResource() after removing the leading slash, I would expect that these calls are identical, but obviously they are not in this case. Even when a special class loader is attached to the particular class, it should still be the same one for each call, again resulting in the same behavior.

So, the question is: are there any obvious circumstances under which the following code returns null for the first call but the proper URL for the second call?

package com.example;  import java.net.URL;  public class ResourceTest {     public void run() {       URL iconUrl1 = getClass().getClassLoader().getResource("path/image.png");       System.out.println("ClassLoader.getResource(\"path/image.png\"): " + iconUrl1);        URL iconUrl2 = getClass().getResource("/path/image.png");       System.out.println("Class.getResource(\"/path/image.png\"): " + iconUrl2);    }     public static void main(String[] args) {       ResourceTest app = new ResourceTest();       app.run();    } } 
like image 568
Andreas Fester Avatar asked Nov 07 '12 12:11

Andreas Fester


People also ask

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

Class. getResources would retrieve the resource by the classloader which load the object. While ClassLoader. getResource would retrieve the resource using the classloader specified.

What does class getResource do?

The getResource() method of java. lang. Class class is used to get the resource with the specified resource of this class. The method returns the specified resource of this class in the form of URL object.

How does getResource work in Java?

The getResource method finds a resource with the specified name. It returns a URL to the resource or null if it does not find the resource. Calling java. net.

What is ClassLoader getSystemResource?

ClassLoader Class getSystemResource() method getSystemResource() method is used to find the system resource of the given resource name from the searching location to load classes.


1 Answers

I thought this question was already asked and answered!

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.
like image 125
paulsm4 Avatar answered Sep 30 '22 22:09

paulsm4