Spring Classpath Resource

0

Spring abstracts out resources like file, classpath, URL etc. using a common interface called Resource. This article shows an example of classpath resource.

What is a ClassPath Resource?

A class path resource is like a class or a resource file and is always identified with respect to a class loader.

Spring Classpath Resource
Spring Classpath Resource

In the below example, we demonstrate how classPathResource picks up the the resource based on the classloader we pass.
The classloader can be a custom classloader or a thread’s context classloader or the classloader that loaded the class which is requesting for the resource.
Let’s first create a resource which we would like to access. In our example, we will build a jar which contains a file called “myResource.properties” in two different paths.
One of the myResource.properties is in the topmost directory and the second one is in sub-directory resources.

Jar’s directory structure

Spring Classpath Resource

Spring Classpath Resource
Jar Command
jar cf test.jar myResource.properties resources/myResource.properties

Resource is in classpath

In the below example, the resource is in classpath and we access the resource using application classloader. We get the resource and load the properties file.

public void testResourceLoadFromClasspath() throws IOException, URISyntaxException {
    Properties prop = new Properties();
    prop.load(getClass().getResourceAsStream("myResource.properties"));
    assertEquals("classpath:myResource.properties", prop.get("path"));
}

Resource in jar file

In the below example, the resource file to be accessed is in a jar and the jar is in the classpath. We create a custom class loader to load the jar. We then create ClassPathResource passing the property file to be accessed and the custom classloader. classpathResource.getInputStream() returns us the input stream.

    
    public void testResourceLoadFromJar() throws IOException, URISyntaxException {
        URLClassLoader classLoader = URLClassLoader.newInstance(new URL[]{getClass().getResource("test.jar").toURI().toURL()});
        ClassPathResource jarResource = new ClassPathResource("myResource.properties", classLoader);
        assertEquals("jar", jarResource.getURL().getProtocol());
        Properties prop = new Properties();
        prop.load(jarResource.getInputStream());
        assertEquals("jar:myResource.properties", prop.get("path"));
    }

Relative Resource in jar file

In the below example, I show you how to access a relative classpath resource.
We read the second myResource.properties file which is in the sub-directory resources within the jar.

    public void testRelativeResourceFromJar() throws IOException, URISyntaxException {
        URLClassLoader classLoader = URLClassLoader.newInstance(new URL[]{getClass().getResource("test.jar").toURI().toURL()});
        ClassPathResource jarResource = new ClassPathResource("myResource.properties", classLoader);
        Properties prop = new Properties();
        Resource relativeResource = jarResource.createRelative("resources/myResource.properties");
        prop.load(relativeResource.getInputStream());
        assertEquals("jar:resources/myResource.properties", prop.get("path"));
    }

Current thread context Classloader

If a classloader is not passed to the classPathResource, by default, first preference is given to the thread context classloader. If it is not set then the classloader of the current class is used. If we want some specific classloader to be used, we just need to set it to the current thread context. In the below test case, we set the jar’s classloader as the thread context class loader.

    public void testDefaultClassLoader() throws IOException, URISyntaxException {
        try {
            Properties prop = new Properties();
            URLClassLoader classLoader = URLClassLoader.newInstance(new URL[]{getClass().getResource("test.jar").toURI().toURL()});
            Thread.currentThread().setContextClassLoader(classLoader);
            prop.load(new ClassPathResource("myResource.properties").getInputStream());
            assertEquals("jar:myResource.properties", prop.get("path"));
        } finally {
            Thread.currentThread().setContextClassLoader(null);
        }
    }

Path name

Path name can have windows style ‘\\’ or the inner simple dots like ‘..’ or ‘.’, ┬áthe path is automatically normalized by spring.

        public void testDifferentPathNames() throws IOException, URISyntaxException {
        URLClassLoader classLoader = URLClassLoader.newInstance(new URL[]{getClass().getResource("test.jar").toURI().toURL()});
        ClassPathResource jarResource = new ClassPathResource("resources/../resources/myResource.properties", classLoader);
        assertEquals("resources/myResource.properties", jarResource.getPath());
        
        jarResource = new ClassPathResource("resources\\myResource.properties", classLoader);
        assertEquals("resources/myResource.properties", jarResource.getPath());
        
        jarResource = new ClassPathResource("\\resources\\myResource.properties", classLoader);
        assertEquals("resources/myResource.properties", jarResource.getPath());
        
        jarResource = new ClassPathResource("/resources/myResource.properties", classLoader);
        assertEquals("resources/myResource.properties", jarResource.getPath());
        
        jarResource = new ClassPathResource("./resources/myResource.properties", classLoader);
        assertEquals("resources/myResource.properties", jarResource.getPath());
        
        jarResource = new ClassPathResource("resources/../resources/./myResource.properties", classLoader);
        assertEquals("resources/myResource.properties", jarResource.getPath());
    }
Share.

Leave A Reply