Spring Top

I just announced the new Learn Spring course, focused on the fundamentals of Spring 5 and Spring Boot 2:

>> CHECK OUT THE COURSE

1. Overview

In this tutorial, we’ll look at various ways to inject the contents of a resource containing text as a String into our Spring beans.

We’ll look at locating the resource and reading its contents.

Also, we’ll demonstrate how to share the loaded resources across several beans. We’ll show this through the use of annotations related to dependency injection, though the same can also be achieved by using XML-based injection and declaring the beans in the XML property file.

2. Using Resource

We can simplify locating a resource file by using the Resource interface. Spring helps us find and read a resource using the resource loader, which decides which Resource implementation to pick depending on the path provided. The Resource is effectively a way of accessing the content of the resource, rather than the content itself.

Let’s see some ways to acquire a Resource instance for resources on the classpath.

2.1. Using ResourceLoader

We can use the class ResourceLoader if we prefer to use lazy loading:

ResourceLoader resourceLoader = new DefaultResourceLoader();
Resource resource = resourceLoader.getResource("classpath:resource.txt");

We can also inject the ResourceLoader into our bean with @Autowired:

@Autowired
private ResourceLoader resourceLoader;

2.2 Using @Resource

We can inject a Resource directly into a Spring bean with @Value:

@Value("classpath:resource.txt")
private Resource resource;

3. Converting from Resource to String

Once we have access to the Resource we need to be able to read it into a String. Let’s create a ResourceReader utility class with a static method asString to do this for us.

First, we have to acquire an InputStream:

InputStream inputStream = resource.getInputStream();

Our next step is to take this InputStream and convert it to a String. We can use Spring’s own FileCopyUtils#copyToString method:

public class ResourceReader {

    public static String asString(Resource resource) {
        try (Reader reader = new InputStreamReader(resource.getInputStream(), UTF_8)) {
            return FileCopyUtils.copyToString(reader);
        } catch (IOException e) {
            throw new UncheckedIOException(e);
        }
    }

    // more utility methods
}

There are many other ways of achieving this, for example, using copyToString of Spring’s StreamUtils class

Let’s also create another utility method readFileToString, which will retrieve the Resource for a path, and call the asString method to convert it to a String.

public static String readFileToString(String path) {
    ResourceLoader resourceLoader = new DefaultResourceLoader();
    Resource resource = resourceLoader.getResource(path);
    return asString(resource);
}

4. Adding a Configuration Class

If each bean had to inject resource Strings individually, there’s a chance of both code duplication and more use of memory by beans having their own individual copy of the String.

We can achieve a neater solution by injecting the resource’s content to one or multiple Spring beans upon loading the application context. In this way, we can hide the implementation details for reading the resource from the various beans which need to use this content.

@Configuration
public class LoadResourceConfig {

    // Bean Declarations
}

4.1. Using a Bean Holding the Resource String

Let’s declare beans to hold the resource content in an @Configuration class:

@Bean
public String resourceString() {
    return ResourceReader.readFileToString("resource.txt");
}

Let’s now inject the registered beans to the fields by adding an @Autowired annotation:

public class LoadResourceAsStringIntegrationTest {
    private static final String EXPECTED_RESOURCE_VALUE = "...";  // The string value of the file content

    @Autowired
    @Qualifier("resourceString")
    private String resourceString;

    @Test
    public void givenUsingResourceStringBean_whenConvertingAResourceToAString_thenCorrect() {
        assertEquals(EXPECTED_RESOURCE_VALUE, resourceString);
    }
}

In this case, we use the @Qualifier annotation and the name of the bean, as we may need to inject multiple fields of the same typeString.

We should note that the bean name used in the qualifier is derived from the name of the method that creates the bean in the configuration class.

5. Using SpEL

Finally, let’s see how we can use the Spring Expression Language to describe the code needed to load a resource file directly into a field in our class.

Let’s use the @Value annotation to inject the file content into the field resourceStringUsingSpel:

public class LoadResourceAsStringIntegrationTest {
    private static final String EXPECTED_RESOURCE_VALUE = "..."; // The string value of the file content

    @Value(
      "#{T(com.baeldung.loadresourceasstring.ResourceReader).readFileToString('classpath:resource.txt')}"
    )
    private String resourceStringUsingSpel;

    @Test
    public void givenUsingSpel_whenConvertingAResourceToAString_thenCorrect() {
        assertEquals(EXPECTED_RESOURCE_VALUE, resourceStringUsingSpel);
    }
}

Here we have called ResourceReader#readFileToString describing the location of the file by using a “classpath:” –prefixed path inside our @Value annotation.

To reduce the amount of code in the SpEL, we’ve created a helper method in the class ResourceReader which uses Apache Commons FileUtils to access the file from the path provided:

public class ResourceReader {
    public static String readFileToString(String path) throws IOException {
        return FileUtils.readFileToString(ResourceUtils.getFile(path), StandardCharsets.UTF_8);
    }
}

6. Conclusion

In this tutorial, we’ve reviewed some of the ways to convert a resource to a String.

First of all, we saw how to produce a Resource to access the file, and how to read from Resource to String.

Next, we also showed how to hide the resource loading implementation, and allow the string contents to be shared across beans by creating qualified beans in an @Configuration, allowing the strings to be autowired.

Finally, we used SpEL, which provides a compact and immediate solution, though it required a custom helper function to stop it from becoming too complex.

As always, the code for the examples can be found over on GitHub

Spring bottom

I just announced the new Learn Spring course, focused on the fundamentals of Spring 5 and Spring Boot 2:

>> CHECK OUT THE COURSE