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

I wonder what the difference is between Class.getResource() and ClassLoader.getResource()?
edit: I especially want to know if any caching is involved on file/directory level. As in "are directory listings cached in the Class version?"
AFAIK the following should essentially do the same, but they are not:
getClass().getResource()
getClass().getClassLoader().getResource()
I discovered this when fiddling with some report generation code that creates a new file in WEB-INF/classes/ from an existing file in that directory. When using the method from Class, I could find files that were there at deployment using getClass().getResource(), but when trying to fetch the newly created file, I recieved a null object. Browsing the directory clearly shows that the new file is there. The filenames were prepended with a forward slash as in "/myFile.txt".
The ClassLoader version of getResource() on the other hand did find the generated file. From this experience it seems that there is some kind of caching of the directory listing going on. Am I right, and if so, where is this documented?
From the API docs on Class.getResource()
Finds a resource
with a given name. The rules for
searching resources associated with a
given class are implemented by the
defining class loader of the class.
This method delegates to this object's
class loader. If this object was
loaded by the bootstrap class loader,
the method delegates to
ClassLoader.getSystemResource(java.lang.String).
To me, this reads "Class.getResource is really calling its own classloader's getResource()". Which would be the same as doing getClass().getClassLoader().getResource(). But it is obviously not. Could someone please provide me with some illumination into this matter?

Class.getResource can take a "relative" resource name, which is treated relative to the class's package. Alternatively you can specify an "absolute" resource name by using a leading slash. Classloader resource paths are always deemed to be absolute.
So the following are basically equivalent:
foo.bar.Baz.class.getResource("xyz.txt");
foo.bar.Baz.class.getClassLoader().getResource("foo/bar/xyz.txt");
And so are these (but they're different from the above):
foo.bar.Baz.class.getResource("/data/xyz.txt");
foo.bar.Baz.class.getClassLoader().getResource("data/xyz.txt");

The first call searches relative to the .class file while the latter searches relative to the classpath root.
To debug issues like that, I print the URL:
System.out.println( getClass().getResource(getClass().getSimpleName() + ".class") );

Had to look it up in the specs:
Class.getResource(String resource)
ClassLoader.getResource(String resource)
Class's getResource() - documentation states the difference:
This method delegates the call to its class loader, after making these changes to the resource name: if the resource name starts with "/", it is unchanged; otherwise, the package name is prepended to the resource name after converting "." to "/". If this object was loaded by the bootstrap loader, the call is delegated to ClassLoader.getSystemResource.

All these answers around here, as well as the answers in this question, suggest that loading absolute URLs, like "/foo/bar.properties" treated the same by class.getResourceAsStream(String) and class.getClassLoader().getResourceAsStream(String). This is NOT the case, at least not in my Tomcat configuration/version (currently 7.0.40).
MyClass.class.getResourceAsStream("/foo/bar.properties"); // works!
MyClass.class.getClassLoader().getResourceAsStream("/foo/bar.properties"); // does NOT work!
Sorry, I have absolutely no satisfying explanation, but I guess that tomcat does dirty tricks and his black magic with the classloaders and cause the difference. I always used class.getResourceAsStream(String) in the past and haven't had any problems.
PS: I also posted this over here

To answer the question whether there is any caching going on.
I investigated this point further by running a stand-alone Java application that continuously loaded a file from disk using the getResourceAsStream ClassLoader method. I was able to edit the file, and the changes were reflected immediately, i.e., the file was reloaded from disk without caching.
However:
I'm working on a project with several maven modules and web projects that have dependencies on each other. I'm using IntelliJ as my IDE to compile and run the web projects.
I noticed that the above seemed to no longer hold true, the reason being that the file that I was being loaded is now baked into a jar and deployed to the depending web project. I only noticed this after trying to change the file in my target folder, to no avail. This made it seem as though there was caching going on.

Since Java 9 there is a pitfall with ClassLoader#getResource when running on the module path. Because of this, I would never use ClassLoader#getResource in new code.
If your code is in a named module, and you use ClassLoader#getResource, your code can fail to retrieve a resource even if the resource is in the same module. This is very surprising behavior.
I experienced this myself and was very surprised as to this difference between Class#getResource and ClassLoader#getResource. However, it is entirely specified behavior according to the javadoc:
Additionally, and except for the special case where the resource has a name ending with ".class", this method will only find resources in packages of named modules when the package is opened unconditionally (even if the caller of this method is in the same module as the resource).
Javadoc (emphasis mine)

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

I tried reading from input1.txt which was inside one of my packages together with the class which was trying to read it.
The following works:
String fileName = FileTransferClient.class.getResource("input1.txt").getPath();
System.out.println(fileName);
BufferedReader bufferedTextIn = new BufferedReader(new FileReader(fileName));
The most important part was to call getPath() if you want the correct path name in String format. DO NOT USE toString() because it will add some extra formatting text which will TOTALLY MESS UP the fileName (you can try it and see the print out).
Spent 2 hours debugging this... :(

Another more efficient way to do is just use #Value
#Value("classpath:sss.json")
private Resource resource;
and after that you can just get the file this way
File file = resource.getFile();

Related

how java find real path of dependency jar file? [duplicate]

System.getProperty("java.class.path") returns the classpath of my program. However getClassLoader().getURLs() is also providing me with the classpath (see my other post: how to use getClassLoader)
What is the difference between the two mentioned ways?
Main difference can be found in what they return:
getClassLoader.getURLs()
Returns the search path of URLs for loading classes and resources. This includes the original list of URLs specified to the constructor, along with any URLs subsequently appended by the addURL() method, see link
System.getProperty("java.class.path")
Path used to find directories and JAR archives containing class files. Elements of the class path are separated by a platform-specific character specified in the path.separator property, see link
Looking at definition, here are the differences:
First one returns an array of URL whereas second one returns a String.
First one will also return any URLs appended in runtime using API, second one will not include that.
More or less it depends on what you are trying to achieve when you have to decide which one to pick.
Cheers !!
One difference is that there is no such method as 'ClassLoader.getURL()'.
The ClassLoader you get the URLs from (although not by the method you mention, which is non-existent), may not have been the system class loader. It may have been for example a URLClassLoader, which has nothing to do with the classpath.
A shot in the dark would be that the ClassLoader would need the class path in order to find what to load, getClassLoader() also calls a native method, the JVM probably grabs the classpath directly and loads it into the class loader.
You're accessing the same data in different ways.

Java resource loading [duplicate]

I wonder what the difference is between Class.getResource() and ClassLoader.getResource()?
edit: I especially want to know if any caching is involved on file/directory level. As in "are directory listings cached in the Class version?"
AFAIK the following should essentially do the same, but they are not:
getClass().getResource()
getClass().getClassLoader().getResource()
I discovered this when fiddling with some report generation code that creates a new file in WEB-INF/classes/ from an existing file in that directory. When using the method from Class, I could find files that were there at deployment using getClass().getResource(), but when trying to fetch the newly created file, I recieved a null object. Browsing the directory clearly shows that the new file is there. The filenames were prepended with a forward slash as in "/myFile.txt".
The ClassLoader version of getResource() on the other hand did find the generated file. From this experience it seems that there is some kind of caching of the directory listing going on. Am I right, and if so, where is this documented?
From the API docs on Class.getResource()
Finds a resource
with a given name. The rules for
searching resources associated with a
given class are implemented by the
defining class loader of the class.
This method delegates to this object's
class loader. If this object was
loaded by the bootstrap class loader,
the method delegates to
ClassLoader.getSystemResource(java.lang.String).
To me, this reads "Class.getResource is really calling its own classloader's getResource()". Which would be the same as doing getClass().getClassLoader().getResource(). But it is obviously not. Could someone please provide me with some illumination into this matter?
Class.getResource can take a "relative" resource name, which is treated relative to the class's package. Alternatively you can specify an "absolute" resource name by using a leading slash. Classloader resource paths are always deemed to be absolute.
So the following are basically equivalent:
foo.bar.Baz.class.getResource("xyz.txt");
foo.bar.Baz.class.getClassLoader().getResource("foo/bar/xyz.txt");
And so are these (but they're different from the above):
foo.bar.Baz.class.getResource("/data/xyz.txt");
foo.bar.Baz.class.getClassLoader().getResource("data/xyz.txt");
The first call searches relative to the .class file while the latter searches relative to the classpath root.
To debug issues like that, I print the URL:
System.out.println( getClass().getResource(getClass().getSimpleName() + ".class") );
Had to look it up in the specs:
Class.getResource(String resource)
ClassLoader.getResource(String resource)
Class's getResource() - documentation states the difference:
This method delegates the call to its class loader, after making these changes to the resource name: if the resource name starts with "/", it is unchanged; otherwise, the package name is prepended to the resource name after converting "." to "/". If this object was loaded by the bootstrap loader, the call is delegated to ClassLoader.getSystemResource.
All these answers around here, as well as the answers in this question, suggest that loading absolute URLs, like "/foo/bar.properties" treated the same by class.getResourceAsStream(String) and class.getClassLoader().getResourceAsStream(String). This is NOT the case, at least not in my Tomcat configuration/version (currently 7.0.40).
MyClass.class.getResourceAsStream("/foo/bar.properties"); // works!
MyClass.class.getClassLoader().getResourceAsStream("/foo/bar.properties"); // does NOT work!
Sorry, I have absolutely no satisfying explanation, but I guess that tomcat does dirty tricks and his black magic with the classloaders and cause the difference. I always used class.getResourceAsStream(String) in the past and haven't had any problems.
PS: I also posted this over here
To answer the question whether there is any caching going on.
I investigated this point further by running a stand-alone Java application that continuously loaded a file from disk using the getResourceAsStream ClassLoader method. I was able to edit the file, and the changes were reflected immediately, i.e., the file was reloaded from disk without caching.
However:
I'm working on a project with several maven modules and web projects that have dependencies on each other. I'm using IntelliJ as my IDE to compile and run the web projects.
I noticed that the above seemed to no longer hold true, the reason being that the file that I was being loaded is now baked into a jar and deployed to the depending web project. I only noticed this after trying to change the file in my target folder, to no avail. This made it seem as though there was caching going on.
Since Java 9 there is a pitfall with ClassLoader#getResource when running on the module path. Because of this, I would never use ClassLoader#getResource in new code.
If your code is in a named module, and you use ClassLoader#getResource, your code can fail to retrieve a resource even if the resource is in the same module. This is very surprising behavior.
I experienced this myself and was very surprised as to this difference between Class#getResource and ClassLoader#getResource. However, it is entirely specified behavior according to the javadoc:
Additionally, and except for the special case where the resource has a name ending with ".class", this method will only find resources in packages of named modules when the package is opened unconditionally (even if the caller of this method is in the same module as the resource).
Javadoc (emphasis mine)
Class.getResources would retrieve the resource by the classloader which load the object. While ClassLoader.getResource would retrieve the resource using the classloader specified.
I tried reading from input1.txt which was inside one of my packages together with the class which was trying to read it.
The following works:
String fileName = FileTransferClient.class.getResource("input1.txt").getPath();
System.out.println(fileName);
BufferedReader bufferedTextIn = new BufferedReader(new FileReader(fileName));
The most important part was to call getPath() if you want the correct path name in String format. DO NOT USE toString() because it will add some extra formatting text which will TOTALLY MESS UP the fileName (you can try it and see the print out).
Spent 2 hours debugging this... :(
Another more efficient way to do is just use #Value
#Value("classpath:sss.json")
private Resource resource;
and after that you can just get the file this way
File file = resource.getFile();

Using the "file:" prefix to file paths in Java filename strings?

Getting resources for Java projects has always been fairly confusing to me, as the documentation doesn't explain it very well in my opinion, and I end up having to re-learn it every time I need to use it in a project. Most recently, using JavaFX, I was trying to load an image. The constructor requires a string representing the file path. I had come up with a very hacky method of doing this in the past, but I recently came across this StackOverflow post, and the accepted answer shows a very simple way of referencing the top level of the Eclipse project so that I can access source folders in the build path and easily locate my image files.
Is there a name for this particular delimeter? Are there other delimeters like it? Would there be problems using this notation when running this code in an executable JAR?
Any information would be greatly appreciated. And if this isn't the best way to approach this and someone could give me an adequate, simple explanation on how to do this in the future or a link to an article that explains it well, that would be great.
You can get resources using a relative path or an absolute path. Relative paths start from the "working directory", which is the directory your application runs from. An absolute path is unambiguous. The working directory is checked before the classpath. This is what is used in places like
new File(filepath).
When you run Java, there is also the classpath to consider. Another way some people look for resources is
ClassLoader.getResource(String)
and
ClassLoader.getResourceAsStream(String)
The ClassLoader can accept the String as a relative path and will check each location along the classpath.
https://docs.oracle.com/javase/7/docs/api/java/lang/ClassLoader.html#getResourceAsStream(java.lang.String)
People get results by putting their files within the src folder because that usually gets copied over to the place where the class files are generated, which is included on the classpath.
The "top level" that you speak of is the working directory. Eclipse sets the working directory to the project root by default.
The relevant wikipedia page covers the file: scheme nicely.
But we live in a messy world, and various pieces of software may conform to older standards, or not conform completely with any standards, or may include support for alternate syntaxes. Understanding the correct syntax to use with a particular software system is unfortunately not always straightforward.

What is the equivalent to python equivalent to using Class.getResource() [duplicate]

This question already has answers here:
Way to access resource files in python
(4 answers)
Closed 9 years ago.
In java if I want to read a file that contains resource data for my algorithms how do I do it so the path is correctly referenced.
Clarification
I am trying to understand how in the Python world one packages data along with code in a module.
For example I might be writing some code that looks at a string and tries to classify the language the text is written in. For this to work I need to have a file that contains data about language models.
So when my code is called I would like to load a file (or files) that is packaged along with the module. I am not clear on how I should do that in Python.
TIA.
I think you may be looking for pkgutil.get_data(). The docs for this say:
pkgutil.get_data(package, resource)
Get a resource from a package.
This is a wrapper for the PEP 302 loader get_data() API. The package
argument should be the name of a package, in standard module format
(foo.bar). The resource argument should be in the form of a relative
filename, using / as the path separator. The parent directory name ..
is not allowed, and nor is a rooted name (starting with a /).
The function returns a binary string that is the contents of the
specified resource.
For packages located in the filesystem, which have already been
imported, this is the rough equivalent of:
d = os.path.dirname(sys.modules[package].__file__)
data = open(os.path.join(d, resource), 'rb').read()
If the package cannot be
located or loaded, or it uses a PEP 302 loader which does not support
get_data(), then None is returned.
I think you are looking for imp.load_source:
import imp
module = imp.load_source('ModuleName', '/path/of/the/file.py')
module.FooBar()
For Pythonistas who don't know, the behaviour of Java's Class.getResource is basically: the supplied file name is (unless it's already an absolute path) transformed into a relative path by using the class' package (since the directory path to the class file is expected to mirror the explicit "package" declaration for the class). The ClassLoader that was used to load the class in the first place then gets to transform this path string, by its own logic, into a URL object that could encode a file name, a location on the WWW, etc.
Python is not Java, so we have to approximate a few things and read intent into the question.
Python classes don't really explicitly go into packages, although you can create packages by putting them in folders with an additional __init__.py file.
Python does not really have anything quite like the URL class in its standard library; although there is plenty of support for connecting to the Internet, you're generally expected to just use strings to represent URLs (and file names) and format them appropriately. This is arguably an unfortunate missed opportunity for polymorphism (it would not be hard to make your own wrapper, though you might miss lots of special cases and useful functionality). Anyway, in normal cases with Java, you're not expecting to get a web URL from this process.
Python has a concept of a "working directory" that depends on how the Python process was launched. File paths are not necessarily relative to the directory where the "main class" (well, really, "main module", because Python doesn't make you put everything in a class) is found.
So what you really want, probably, is to get the absolute path on disk to the source file corresponding to the class. But that isn't really going to work out either. The problem is: given a class, you can get the name of the module it comes from, and then look up that name to get the actual module object, and then from the module object get the file name that the module was loaded from. However, that file name is relative to whatever the working directory was when the module was loaded, and that information isn't recorded. If the working directory has changed since then (with os.chdir), you're out of luck.
Please try to be more clear about what you're really trying to do.

Using the ClassLoader method to retrieve all resources under classes as Input Streams

My problem is one that you would think is quite common, but I haven't so far managed to find a solution.
Building a Java web app under Tomcat 5.5 (although a requirement is that it can be deployed anywhere, like under a WebLogic environment, hence the loading resources as streams requirement). Good practice dictates that resource files are placed under WEB-INF/classes and loaded using the ClassLoader's getResourceAsStream() method. All well and good when you know the name of the resource you want to load.
My problem is that I need to load everything (including recursively in non-empty sub-directories) that lives in a subdirectory of classes.
So, for example, if I have the following under WEB-INF/classes:
folderX/folderY
folderX/folderY/fileA.properties
folderX/fileB.properties
I need the fileA.properties and fileB.properties classes to be loaded, without actually knowing their names before the application is started (ie I need the ability to arbitrarily load resources from any directory under WEB-INF/classes).
What is the most elegant way to do this? What object could I interrogate to find the information I need (the resource paths to each of the required resources)? A non-servlet specific solution would be best (keeping it all within the class loading framework if possible).
Thanks in advance!
As far as I am aware, there is no such ability, since the classloader only attempts to load things it is asked for. It doesn't pre-fetch all items on the classpath, or treat them as a directory structure.
The way I would solve the problem is create a directory listing in a text file of all relevant resources at build time and include that in the war, and then walk it through that way.
You can do that with some tricks :)
Get the resource as URL, extract the protocol :
file protocol - get the URL path and you have a folder, scan for files.
jar/zip protocol - extract the jar/zip path and use JarFile to browse the files and extract everything under your path/package.

Categories