### 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`
1. Use framework facilities to get the resource
## Example: read file from `resources`
```java
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`](
[To see links please register here]
) is Spring's implementation of `Resource` - the abstract way to load _resource_. It is instantiated using the [`ClassPathResource(String, Class<?>)`](
[To see links please register here]
) constructor:
* `/hello` is a path to the file
* The leading slash loads file by absolute path in classpath
* It is required because otherwise the path would be relative to the class
* If you pass a `ClassLoader` instead of `Class`, the slash can be omitted
* See also [What is the difference between Class.getResource() and ClassLoader.getResource()?](
[To see links please register here]
)
* The second argument is the `Class` to load the resource by
* Prefer passing the `Class` instead of `ClassLoader`, because [`ClassLoader.getResource` differs from `Class.getResource` in JPMS](
[To see links please register here]
)
* 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:
```java
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`](
[To see links please register here]
) method: it accepts `URL`
###### Use framework's facilities to get the resource:
Spring Framework enables access to classpath resources through [`ClassPathResource`](
[To see links please register here]
)
You can use it:
1. Directly, as in the example of reading file from `resources`
1. Indirectly:
1. Using [`@Value`](
[To see links please register here]
):
```java
@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);
}
}
}
```
1. Using [`ResourceLoader`](
[To see links please register here]
):
```java
@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](
[To see links please register here]
) answer