Read file from resources folder in Spring Boot

JavaSpringSpring BootJson Schema-Validator

Java Problem Overview


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?

Java Solutions


Solution 1 - Java

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 - Java

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:

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 - Java

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 - Java

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

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

Solution 5 - Java

2021 The Best Way


Simplest way to read file is:

    Resource resource = new ClassPathResource("jsonSchema.json");
    FileInputStream file = new FileInputStream(resource.getFile());

Solution 6 - Java

See my answer here: https://stackoverflow.com/a/56854431/4453282

import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;

Use these 2 imports.

Declare

@Autowired
ResourceLoader resourceLoader;

Use this in some function

Resource resource=resourceLoader.getResource("classpath:preferences.json");

In your case, as you need the file you may use following

File file = resource.getFile()

Reference:http://frugalisminds.com/spring/load-file-classpath-spring-boot/ As already mentioned in previous answers don't use ResourceUtils it doesn't work after deployment of JAR, this will work in IDE as well as after deployment

Solution 7 - Java

Below is my working code.

List<sampleObject> list = new ArrayList<>();
File file = new ClassPathResource("json/test.json").getFile();
ObjectMapper objectMapper = new ObjectMapper();
sampleObject = Arrays.asList(objectMapper.readValue(file, sampleObject[].class));

Hope it helps one!

Solution 8 - Java

stuck in the same issue, this helps me

URL resource = getClass().getClassLoader().getResource("jsonschema.json");
JsonNode jsonNode = JsonLoader.fromURL(resource);

Solution 9 - Java

create json folder in resources as subfolder then add json file in folder then you can use this code : enter image description here

import com.fasterxml.jackson.core.type.TypeReference;

InputStream is = TypeReference.class.getResourceAsStream("/json/fcmgoogletoken.json");

this works in Docker.

Solution 10 - Java

Here is my solution. May help someone;

It returns InputStream, but i assume you can read from it too.

InputStream is = Thread.currentThread().getContextClassLoader().getResourceAsStream("jsonschema.json");

Solution 11 - Java

How to get resource reliably

To reliably get a file from the resources in Spring Boot application:

  1. Find a way to pass abstract resource, for example, InputStream, URL instead of File
  2. Use framework facilities to get the resource

Example: read file from resources

public class SpringBootResourcesApplication {
    public static void main(String[] args) throws Exception {
        ClassPathResource resource = new ClassPathResource("/hello", SpringBootResourcesApplication.class);
        try (InputStream inputStream = resource.getInputStream()) {
            String string = new String(inputStream.readAllBytes(), StandardCharsets.UTF_8);
            System.out.println(string);
        }
    }
}
  • ClassPathResource is Spring's implementation of Resource - the abstract way to load resource. It is instantiated using the ClassPathResource(String, Class<?>) constructor:

  • Project structure:

    ├── mvnw
    ├── mvnw.cmd
    ├── pom.xml
    └── src
        └── main
            ├── java
            │   └── com
            │       └── caco3
            │           └── springbootresources
            │               └── SpringBootResourcesApplication.java
            └── resources
                ├── application.properties
                └── hello
    

The example above works from both IDE and jar

Deeper explanation
Prefer abstract resources instead of File
  • Examples of abstract resources are InputStream and URL
  • Avoid using File because it is not always possible to get it from a classpath resource
    • E.g. the following code works in IDE:
    public class SpringBootResourcesApplication {
        public static void main(String[] args) throws Exception {
            ClassLoader classLoader = SpringBootResourcesApplication.class.getClassLoader();
            File file = new File(classLoader.getResource("hello").getFile());
            
            Files.readAllLines(file.toPath(), StandardCharsets.UTF_8)
                    .forEach(System.out::println);
        }
    }
    
    but fails with:
    java.nio.file.NoSuchFileException: file:/home/caco3/IdeaProjects/spring-boot-resources/target/spring-boot-resources-0.0.1-SNAPSHOT.jar!/BOOT-INF/classes!/hello
            at java.base/sun.nio.fs.UnixException.translateToIOException(UnixException.java:92)
            at java.base/sun.nio.fs.UnixException.rethrowAsIOException(UnixException.java:111)
            at java.base/sun.nio.fs.UnixException.rethrowAsIOException(UnixException.java:116)
    
    when Spring Boot jar run
  • If you use external library, and it asks you for a resource, try to find a way to pass it an InputStream or URL
    • For example the JsonLoader.fromFile from the question could be replaced with JsonLoader.fromURL method: it accepts URL
Use framework's facilities to get the resource:

Spring Framework enables access to classpath resources through ClassPathResource

You can use it:

  1. Directly, as in the example of reading file from resources
  2. Indirectly:
    1. Using @Value:
      @SpringBootApplication
      public class SpringBootResourcesApplication implements ApplicationRunner {
          @Value("classpath:/hello") // Do not use field injection
          private Resource resource;
      
          public static void main(String[] args) throws Exception {
              SpringApplication.run(SpringBootResourcesApplication.class, args);
          }
      
         @Override
         public void run(ApplicationArguments args) throws Exception {
             try (InputStream inputStream = resource.getInputStream()) {
                 String string = new String(inputStream.readAllBytes(), StandardCharsets.UTF_8);
                 System.out.println(string);
             }
         }
      }
      
    2. Using ResourceLoader:
      @SpringBootApplication
      public class SpringBootResourcesApplication implements ApplicationRunner {
          @Autowired // do not use field injection
          private ResourceLoader resourceLoader;
      
          public static void main(String[] args) throws Exception {
              SpringApplication.run(SpringBootResourcesApplication.class, args);
          }
      
          @Override
          public void run(ApplicationArguments args) throws Exception {
              Resource resource = resourceLoader.getResource("/hello");
              try (InputStream inputStream = resource.getInputStream()) {
                  String string = new String(inputStream.readAllBytes(), StandardCharsets.UTF_8);
                  System.out.println(string);
              }
          }
      }
      
      • See also this answer

Solution 12 - Java

The simplest method to bring a resource from the classpath in the resources directory parsed into a String is the following one liner.

As a String(Using Spring Libraries):

         String resource = StreamUtils.copyToString(
                new ClassPathResource("resource.json").getInputStream(), defaultCharset());

This method uses the StreamUtils utility and streams the file as an input stream into a String in a concise compact way.

If you want the file as a byte array you can use basic Java File I/O libraries:

As a byte array(Using Java Libraries):

byte[] resource = Files.readAllBytes(Paths.get("/src/test/resources/resource.json"));

Solution 13 - Java

Spring provides ResourceLoader which can be used to load files.

@Autowired
ResourceLoader resourceLoader;


// path could be anything under resources directory
File loadDirectory(String path){
        Resource resource = resourceLoader.getResource("classpath:"+path); 
        try {
            return resource.getFile();
        } catch (IOException e) {
            log.warn("Issue with loading path {} as file", path);
        }
        return null;
 }

Referred to this link.

Solution 14 - Java

For me, the bug had two fixes.

  1. Xml file which was named as SAMPLE.XML which was causing even the below solution to fail when deployed to aws ec2. The fix was to rename it to new_sample.xml and apply the solution given below.
  2. Solution approach https://medium.com/@jonathan.henrique.smtp/reading-files-in-resource-path-from-jar-artifact-459ce00d2130

I was using Spring boot as jar and deployed to aws ec2 Java variant of the solution is as below :

package com.test;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.core.io.Resource;


public class XmlReader {
	
	private static Logger LOGGER = LoggerFactory.getLogger(XmlReader.class);

  public static void main(String[] args) {
	  

      String fileLocation = "classpath:cbs_response.xml";
      String reponseXML = null;
      try (ClassPathXmlApplicationContext appContext = new ClassPathXmlApplicationContext()){
        
        Resource resource = appContext.getResource(fileLocation);
        if (resource.isReadable()) {
          BufferedReader reader =
              new BufferedReader(new InputStreamReader(resource.getInputStream()));
          Stream<String> lines = reader.lines();
          reponseXML = lines.collect(Collectors.joining("\n"));
          
        }      
      } catch (IOException e) {
        LOGGER.error(e.getMessage(), e);
      }
  }
}

Solution 15 - Java

If you're using spring and jackson (most of the larger applications will), then use a simple oneliner:

JsonNode json = new ObjectMapper().readTree(new ClassPathResource("filename").getFile());

Solution 16 - Java

If you are using maven resource filter in your proyect, you need to configure what kind of file is going to be loaded in pom.xml. If you don't, no matter what class you choose to load the resource, it won't be found.

pom.xml

<resources>
	<resource>
		<directory>${project.basedir}/src/main/resources</directory>
		<filtering>true</filtering>
		<includes>
			<include>**/*.properties</include>
			<include>**/*.yml</include>
			<include>**/*.yaml</include>
			<include>**/*.json</include>
		</includes>
	</resource>
</resources>

Solution 17 - Java

Below works in both IDE and running it as a jar in the terminal,

import org.springframework.core.io.Resource;

@Value("classpath:jsonschema.json")
Resource schemaFile;
    
JsonSchemaFactory factory = JsonSchemaFactory.getInstance(SpecVersion.VersionFlag.V4);
JsonSchema jsonSchema = factory.getSchema(schemaFile.getInputStream());

Solution 18 - Java

i think the problem lies within the space in the folder-name where your project is placed. /home/user/Dev/Java/Java%20Programs/SystemRoutines/target/classes/jsonschema.json

there is space between Java Programs.Renaming the folder name should make it work

Solution 19 - Java

Using Spring ResourceUtils.getFile() you don't have to take care absolute path :)

 private String readDictionaryAsJson(String filename) throws IOException {
    String fileContent;
    try {
        File file = ResourceUtils.getFile("classpath:" + filename);
        Path path = file.toPath();
        Stream<String> lines = Files.lines(path);
        fileContent = lines.collect(Collectors.joining("\n"));
    } catch (IOException ex) {
        throw ex;
    }
    return new fileContent;
}

Solution 20 - Java

Try this:

In application.properties

app.jsonSchema=classpath:jsonschema.json

On your Properties pojo:

NOTE: You can use any prefered way of reading configs from application.properties.

@Configuration
@ConfigurationProperties(prefix = "app") 
public class ConfigProperties {
private Resource jsonSchema;

// standard getters and setters
}

In your class, read the resource from the Properties Pojo:

//Read the Resource and get the Input Stream
try (InputStream inStream = configProperties.getJsonSchema().getInputStream()) {
   //From here you can manipulate the Input Stream as desired....
   //Map the Input Stream to a Map
    ObjectMapper mapper = new ObjectMapper();
    Map <String, Object> jsonMap = mapper.readValue(inStream, Map.class);
    //Convert the Map to a JSON obj
    JSONObject json = new JSONObject(jsonMap);
    } catch (Exception e) {
        e.printStackTrace();
    }

Solution 21 - Java

You need to sanitize the path and replace %20 with a space, or rename your directory. Then it should work.

FileNotFoundException: /home/user/Dev/Java/Java%20Programs/SystemRoutines/target/classes/jsonschema.json

Solution 22 - Java

just to add my solution as another 2 cents together with all other answers. I am using the Spring DefaultResourceLoader to get a ResourceLoader. Then the Spring FileCopyUtils to get the content of the resource file to a string.

import static java.nio.charset.StandardCharsets.UTF_8;

import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.io.UncheckedIOException;

import org.springframework.core.io.DefaultResourceLoader;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.util.FileCopyUtils;

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

    private 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);
        }
    }
}

Solution 23 - Java

Here is a solution with ResourceUtils and Java 11 Files.readString which takes care of UTF-8 encoding and resource closing

import org.json.JSONObject;
import org.springframework.util.ResourceUtils;
 
public JSONObject getJsonData() throws IOException {
        //file path : src/main/resources/assets/data.json
        File file = ResourceUtils.getFile("classpath:assets/data.json");
        String data = Files.readString(file.toPath());
        return new JSONObject(data);
 }

But after deploying the application on OpenShift, the resource is not reachable. So the correct solution is

import static java.nio.charset.StandardCharsets.UTF_8;
import static org.springframework.util.FileCopyUtils.copyToByteArray;
import org.springframework.core.io.ClassPathResource;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;

public  JsonNode getJsonData() throws IOException {
  ClassPathResource classPathResource = new 
  ClassPathResource("assets/data.json");
        byte[] byteArray = 
  copyToByteArray(classPathResource.getInputStream());
        return new ObjectMapper() //
                .readTree(new String(byteArray, UTF_8));
}

Solution 24 - Java

I had same issue and because I just had to get file path to send to file input stream, I did this way.

    String pfxCertificate ="src/main/resources/cert/filename.pfx";
    String pfxPassword = "1234";
    FileInputStream fileInputStream = new FileInputStream(pfxCertificate));

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
Questiong3blvView Question on Stackoverflow
Solution 1 - JavaJohnView Answer on Stackoverflow
Solution 2 - JavaSerhii PovísenkoView Answer on Stackoverflow
Solution 3 - JavaIsmailView Answer on Stackoverflow
Solution 4 - JavaEmmanuel OsimosuView Answer on Stackoverflow
Solution 5 - JavaTaha MalikView Answer on Stackoverflow
Solution 6 - Javasajal rajabhojView Answer on Stackoverflow
Solution 7 - JavaBhaumik ThakkarView Answer on Stackoverflow
Solution 8 - JavaGovind SinghView Answer on Stackoverflow
Solution 9 - JavaMostafaMashayekhiView Answer on Stackoverflow
Solution 10 - JavaErçin AkçayView Answer on Stackoverflow
Solution 11 - JavaDenisView Answer on Stackoverflow
Solution 12 - JavaanataliocsView Answer on Stackoverflow
Solution 13 - Javarai.skumarView Answer on Stackoverflow
Solution 14 - JavaVijayakumar SView Answer on Stackoverflow
Solution 15 - JavamembersoundView Answer on Stackoverflow
Solution 16 - JavaJ. EscribanoView Answer on Stackoverflow
Solution 17 - JavaPonsView Answer on Stackoverflow
Solution 18 - JavasamView Answer on Stackoverflow
Solution 19 - JavaszachMatiView Answer on Stackoverflow
Solution 20 - JavaSylvesterView Answer on Stackoverflow
Solution 21 - JavaAndreiView Answer on Stackoverflow
Solution 22 - JavaKnoblauchView Answer on Stackoverflow
Solution 23 - JavaJafar KaruthedathView Answer on Stackoverflow
Solution 24 - JavaKiran MaharjanView Answer on Stackoverflow