javaspring-bootjava-resources

Spring ResourceUtils showing strange behavior loading a test resource as a File


Java 11 and Spring Boot here. I have the following project directory structure:

myapp/
  application.yml
  app/
    src/
      main/
        java/
        resources/
      test/
        java/
        resources/
          smoke/
            file1.txt

I have some code:

File resourceFile = org.springframework.util.ResourceUtils.getFile("smoke/file1.txt");
String filePath = resourceFile.getAbsolutePath();

At runtime, filePath has a value of:

/Users/myuser/workspace/myapp/app/checksum-tests/test-file.txt

When it should be:

/Users/myuser/workspace/myapp/app/src/test/resources/checksum-tests/test-file.txt

Why is this? And more importantly, how can I use ResourceUtils or something similar in Spring-land to fetch a valid (exists on the file system) File to a test resource?


Solution

  • As mentioned in the Spring Documentation for ResourceUtils

    Utility methods for resolving resource locations to files in the file system. Mainly for internal use within the framework. Consider using Spring's Resource abstraction in the core package for handling all kinds of file resources in a uniform manner. ResourceLoader's getResource() method can resolve any location to a Resource object, which in turn allows one to obtain a java.io.File in the file system through its getFile() method.

    In the JavaDoc of ResourceUtils it says

    Does not check whether the file actually exists; simply returns the File that the given location would correspond.

    So using ResourceUtils is not recommended. There are many ways to getting the files. You can use Spring's ResourceLoader if you want spring implementation

    @Autowired
    ResourceLoader resourceLoader;
    

    And in the method you can use

    Resource  resource = resourceLoader.getResource("classpath:smoke/test-file.txt");
    if(resource.exists()){
     System.out.println(resource.getFile().getAbsolutePath());
    }
    

    Or you can use ClassLoader

    ClassLoader classLoader = getClass().getClassLoader();
    File file = new File(classLoader.getResource(resourceName).getFile());
    String absolutePath = file.getAbsolutePath();
    

    If you use Spring Boot then this should give a path with in the target folder.This is because the ClassLoader looks for the resources on the classpath. In Maven, the compiled classes and resources are put in the /target/ directory. That's why this time, we get a path to a classpath resource.
    E.g. D:\file-tester\target\classes\smoke\test-file.txt