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, whileClassLoader.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.
Apache CLI, Executable jar, classLoader().getResource()
I'm posting this as answer as well after discussion via comments:
Classloader.getResource()
is only fetching files that are packaged as part of the Jar-file or located in the classpath-folders.
For reading a normal file you would use something like your first example, i.e. FileReader
or FileInputStream
or simply pass a java.io.File
depending on what the library that you are trying to use supports.
Why to use java.lang.ClassLoader.getResource for resource within jar
File, FileInputStream, FileUtils et cetera are intended to access the file system, and a "file" that is embedded inside a JAR is not actually a file from the file system's point of view. Thus, you can only access those embedded files through tools that are actually intended to read from inside an archive (a JAR is just a fancy ZIP, basically).
Incidentally, the fact that your File object in Java is non-null does not mean the file actually exists. You could do this just fine:
File file = new File("I:\\do\\not.exist");
and file
would be non-null (but isReadable()
and isExist()
should be false). Which is the same behaviour you get for your resource.
It likely works in the IDE because the file does actually exist as a non-archived file in your workspace.
A strange behaviour of Class.getResource()
Probably by some Netbeans compile/clean glitch, the "on.png" was not in the classes directory and therefore was not found on the classpath. After a restart or any operation that would cause Netbeans to rescan the source folders, it was back there.
By the way instead of Class.class.getResource()
you should use the caller's class, e.g. this.getClass().getResource()
to use the same class loader.
Related Topics
Setting Print Size of a Jlabel and Put a Jradiobutton on the Print
Create Custom Annotation for Lombok
Pros and Cons of Package Private Classes in Java
Are Thread.Sleep(0) and Thread.Yield() Statements Equivalent
How to Cause a Child Process to Exit When the Parent Does
Java.Sql.Sqlexception: No Suitable Driver Found for Jdbc:Mysql://Localhost:3306/Dbname
Incompatible Jvm in Ggts (Eclipse) and Java 1.8
Import Com.Sun.Image.Codec.Jpeg.*
File Upload Using Selenium Webdriver and Java Robot Class
Mockito: Mock Private Field Initialization
Create File with Given Size in Java
What Do Curly Braces in Java Mean by Themselves
How to Test Abstract Class in Java with Junit
How to Attach Source or Javadoc in Eclipse for Any Jar File E.G. Javafx