Read file from resources folder in Spring Boot

I'm using Spring Boot and json-schema-validator. I'm trying to read a file called jsonschema.json from the resources folder. I've tried a few different ways but I can't get it to work. This is my code.

ClassLoader classLoader = getClass().getClassLoader();
File file = new File(classLoader.getResource("jsonschema.json").getFile());
JsonNode mySchema = JsonLoader.fromFile(file);

This is the location of the file.

enter image description here

And here I can see the file in the classes folder.

enter image description here

But when I run the code I get the following error.

jsonSchemaValidator error: java.io.FileNotFoundException: /home/user/Dev/Java/Java%20Programs/SystemRoutines/target/classes/jsonschema.json (No such file or directory)

What is it I'm doing wrong in my code?


Solution 1:

After spending a lot of time trying to resolve this issue, finally found a solution that works. The solution makes use of Spring's ResourceUtils. Should work for json files as well.

Thanks for the well written page by Lokesh Gupta : Blog

enter image description here

package utils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.ResourceUtils;

import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
import java.io.File;


public class Utils {

    private static final Logger LOGGER = LoggerFactory.getLogger(Utils.class.getName());

    public static Properties fetchProperties(){
        Properties properties = new Properties();
        try {
            File file = ResourceUtils.getFile("classpath:application.properties");
            InputStream in = new FileInputStream(file);
            properties.load(in);
        } catch (IOException e) {
            LOGGER.error(e.getMessage());
        }
        return properties;
    }
}

To answer a few concerns on the comments :

Pretty sure I had this running on Amazon EC2 using java -jar target/image-service-slave-1.0-SNAPSHOT.jar

Look at my github repo : https://github.com/johnsanthosh/image-service to figure out the right way to run this from a JAR.

Solution 2:

Very short answer: you are looking for the resource in the scope of a classloader's class instead of your target class. This should work:

File file = new File(getClass().getResource("jsonschema.json").getFile());
JsonNode mySchema = JsonLoader.fromFile(file);

Also, that might be helpful reading:

  • What is the difference between Class.getResource() and ClassLoader.getResource()?
  • Strange behavior of Class.getResource() and ClassLoader.getResource() in executable jar
  • Loading resources using getClass().getResource()

P.S. there is a case when a project compiled on one machine and after that launched on another or inside Docker. In such a scenario path to your resource folder would be invalid and you would need to get it in runtime:

ClassPathResource res = new ClassPathResource("jsonschema.json");    
File file = new File(res.getPath());
JsonNode mySchema = JsonLoader.fromFile(file);

Update from 2020

On top of that if you want to read resource file as a String, for example in your tests, you can use these static utils methods:

public static String getResourceFileAsString(String fileName) {
    InputStream is = getResourceFileAsInputStream(fileName);
    if (is != null) {
        BufferedReader reader = new BufferedReader(new InputStreamReader(is));
        return (String)reader.lines().collect(Collectors.joining(System.lineSeparator()));
    } else {
        throw new RuntimeException("resource not found");
    }
}

public static InputStream getResourceFileAsInputStream(String fileName) {
    ClassLoader classLoader = {CurrentClass}.class.getClassLoader();
    return classLoader.getResourceAsStream(fileName);
}

Example of usage:

String soapXML = getResourceFileAsString("some_folder_in_resources/SOPA_request.xml");

Solution 3:

if you have for example config folder under Resources folder I tried this Class working perfectly hope be useful

File file = ResourceUtils.getFile("classpath:config/sample.txt")

//Read File Content
String content = new String(Files.readAllBytes(file.toPath()));
System.out.println(content);

Solution 4:

Spent way too much time coming back to this page so just gonna leave this here:

File file = new ClassPathResource("data/data.json").getFile();