Question

what is the difference between

getClass().getResource("some-resource-file.txt")

vs

Thread.currentThread().getContextClassLoader().getResource("some-resource-file.txt")

I have resources in src/test/resources & I am trying to access them from Unit test. It's a typical maven style directory structure.

I was expecting both to behave identical. But it's not., getClass().getResource() doesn't fetch the resource where as from Thread I am able to fetch the resource.

So how do they differ ?

Was it helpful?

Solution 2

There is a special case getting the first class running (which is why you have to declare the main() method as static with an array of strings as an argument). Once that class is loaded and is running, future attempts at loading classes are done by the class loader. At its simplest, a class loader creates a flat name space of class bodies that are referenced by a string name. Each class in Java uses own classloader to load other classes. So if ClassA.class references ClassB.class then ClassB needs to be on the classpath of the ClassLoader of ClassA, or its parents.

The thread context ClassLoader is a special one in that it is the current ClassLoader for the currently running thread. This is useful in multi-classloader environments. An object can be created from a class in ClassLoader C and then passed to a thread owned by ClassLoader D. In this case the object needs to use Thread.currentThread().getContextClassLoader() directly if it wants to load resources that are not available on its own ClassLoader .

OTHER TIPS

Let's say you're developing a library and the library jar is placed into a web container's classpath.

Now let's say a webapp, using this library, is deployed in the container.

The webapp will have its own class loader, using WEB-INF/classes and WEB-INF/lib/*.jar as its classpath. And the container, for each request coming to your webapp, will set the current thread classloader to the class loader of the classpath.

When your library code uses getClass().getResource(), it will load the resource using the classloader used to load the library classes. It will thus use the container's class loader, and will thus use the resources in your library's jar and in the other libraries used to start the container.

If your library code uses Thread.currentThread().getContextClassLoader() instead to load the resource, it will use the classloader associated with the current thread, and will thus load the resources from the webapp's class loader, looking for the resource in WEB-INF/classes and in the jars inside WEB-INF/lib.

The latter can be what you want. For example, if you're designing a logging library (please don't), the logger will be able to read a different configuration file for each webapp, instead of having a single config shared by all the webapps.

Regarding the way the two methods look for resources, they all finally delegate to a ClassLoader to load the resource. But loading it via a Class will treat relative paths as relative to the invoked class, whereas loading it via a ClassLoader expects a path starting at the root of the package tree. Suppose your class is in the package com.foo, then

 MyClass.class.getResource("hello.txt")

is equivalent to

MyClass.class.getResource("/com/foo/hello.txt")

and is equivalent to

MyClass.class.getClassLoader().getResource("com/foo/hello.txt");
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top