Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Java resource from class vs Thread

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 ?

like image 936
Sairam Krish Avatar asked Mar 26 '14 06:03

Sairam Krish


1 Answers

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");
like image 158
JB Nizet Avatar answered Oct 16 '22 06:10

JB Nizet