Friday, October 18, 2013

Spring Classpath Resource

This article describes the various resource sources like file, class path, url etc. that spring abstracts out using a common interface Resource.

ClassPath Resource

A class path resource like a class or a resource file 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.
Let's first 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

Test case

Resource in classpath

Below is a simple test case to read the properties file from class path.

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

Now we modify the test case to read the properties file from the jar.

    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

Next, we would like to 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());
    }

Home 

No comments:

Post a Comment