Spring Boot ResourceLoader not loading files from main resources in test context - java

I have a class using ResourceLoader for loading file in my src/main/resources directory.
ResourceLoader resourceLoader = new DefaultResourceLoader(MyClass.class.getClassLoader());
Resource resource = resourceLoader.getResource(path);
File file = resource.getFile();
return new String(Files.readAllBytes(file.toPath()));
This works fine when running the app but I also have a #SpringBootTest integration test using the same code. I would like to load the same resource from main/resources but it never finds the file on the provided path. It only works for files places in src/test/resources in that context.
Does anybody know how to force the integration test to search for resources in main resource directory instead of the test one when using ResourceLoader?

Related

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

Load resource in a jar file Java Spring

I want to load a html file located in:
to use in standalone spring boot jar application.
This approach leads to FileSystemNotFoundException
new InputStreamReader(
getClass().getResourceAsStream("/email-templates/html-email.html")
)
Using
#Autowired
private ResourceLoader resourceLoader;
...
resourceLoader.getResource("classpath:email-templates/html-email.html");
leads to NullPointerException.
Could you please specify how to properly load a file in spring boot jar.
Try below code. Using spring classpathresource you should be able to load them. As long as you try load this file inside spring context, Spring container is aware of its classpath .So it should load corresponding file.Otherwise , it tries to find in file system.
Resource resource = new ClassPathResource("email-templates/html-email.html");
I assume you have these resouces in your jar, Check inside the jar file if those resources are present.
jar tf springboot.jar
Load resource in a jar file Java Spring
Try through below code.
ClassLoader classloader = Thread.currentThread().getContextClassLoader();
InputStream is = classloader.getResourceAsStream("email-templates/html-email.html");
/email-templates/html-email.html
If the above doesn't work visit this help full link
Java ClassLoaderUtil

Where is the relative path to a packaged Spring Boot application

How/Where can I set the relative path location for a packaged (jar) Spring Boot jar application?
The following is what works in my IDE (IntelliJ).
I have in my application.properties file the following properties.
converter.output=upload-dir/output/
converter.input=upload-dir
I have a Java class that controls the properties for me.
#Component
#ConfigurationProperties("converter")
public class ConverterProperties {
//getters
//setters
}
I have the following directory structure within the IDE.
src/
target/
upload-dir/
upload-dir/output/
pom.xml
README.txt
However, I am wanting to know where my upload-dir and upload-dir/output folders would be when I generate a jar and run it from a folder? I have tried putting the folder in the same location as the jar
C:\app\app.jar
C:\app\upload-dir\
C:\app\upload-dir\output\
But no dice. I setup the #ConfigurationProperties based on this documentation. https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html, but I can't seem to find anywhere in there were it talks about packaged jar relative paths.
A typical spring boot application displays some of the information you are looking for in the first line at info level (Starting Application {name} on {host} with PID 1234 ({jarpath} started by {user} in {workdir})
Looking at the source code in StartupInfoLogger, it looks like you need to use the ApplicationHome helper class (in package org.springframework.boot) in order to get that absolute path of the JAR file of your running spring boot application.
Here is an example of Java code to retrieve the location of the jar file and the directory containing the jar file. This is then used to create the uploadDir file (assuming it is a subdirectory of the jar directory)
ApplicationHome home = new ApplicationHome(this.getClass());
File jarFile = home.getSource();
File jarDir = home.getDir();
File uploadDir = new File(jarDir, "upload-dir");
You would want to run this from within one of your application classes running in the spring boot app. Looks like it uses the class passed to the constructor of ApplicationHome in order to find the jar which contains that class.

How to edit file in resources of Spring MVC?

I have a project on Spring MVC, The resources folder added to buildpath of Spring.
Project Structure
On some UI action i want to edit the file resources/thirdparty/thirdparty.er from the controller.
So here are the code is tried
File inputFile = new File("/home/local/<User>/Desktop/workspace/<ProjectName>/WebContent/resources/thirdparty/thirdparty.er");
result - it worked fine
Instead of absolute path i wanted a relative path so i tried
File inputFile = new File("../../<something>/WebContent/resources/thirdparty/thirdparty.er");
result - it worked fine, but the path was relative to eclipse(base path), as i was executing code in eclipse
To remove eclipse path dependency, i tried
File inputFile = new File("/resources/thirdparty/thirdparty.er");
result - it didnot worked
Later on searching web, i found
Resource resource = new ClassPathResource("/thirdparty/thirdparty.ER");
File inputFile = resource.getFile();
result - it is returning
/home/local//Desktop/workspace/.metadata/.plugins/org.eclipse.wst.server.core/tmp0/wtpwebapps//WEB-INF/classes/thirdparty/thirdparty.er
which actually isn't the file i want to edit.
Please let me know how this can be done. I donot want any path dependencies on eclipse, server or the system, it sould be completely based on project.
Maybe all you need is
Resource resource = resourceLoader.getResource("classpath:/thirdparty/thirdparty.ER");
and just autowire the resource loader like that:
#Autowired
private ResourceLoader resourceLoader;

Loading a jar's context.xml from classpath

I'm trying to load an application context which is inside a jar as a plugin. I use this to load the context:
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath*:**my-context.xml");
When I load the jar through pom.xml, it works fine.
Then I add it directly in the classpath using eclipse instead of maven to avoid to compile every time (ultimate goal is the shared lib folder in tomcat, not working too). Now spring is unable to find it and return a default context (no exception)
I checked that it's correctly insert in the classpath using:
InputStream in1 = this.getClass().getClassLoader().getResourceAsStream("my-context.xml");
It works.
I checked logs. Using the pom.xml, spring is correctly searching in the jar
Searching directory [...target\classes\META-INF\maven\x.y.z] for files matching pattern [...\x.y.z/target/classes/**/my-context.xml]
Searching directory [...ehealth.poc.module1] for files matching pattern [D:/JRB/Projects/Vivates/workspaces/default/extcom/ehealth.poc.module1/target/classes/**/ecm-context.xml]
...
Resolved location pattern [classpath*:**/my-context.xml] to resources [file [...\target\classes\my-context.xml]]
Loading XML bean definitions from file [...\target\classes\my-context.xml]
...
In the second case, nothing in the log about my jar.
Why spring does not have the same behavior when I use maven or directly the classpath? I maven doing something else than simple adding dependencies location in the classpath?
Finally, we found the solution on eclipse.
The problem comes from the ** in
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath*:**my-context.xml");
It looks like ** doesn't scan the .jar files. Setting the direct path is working :
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("classpath:my-context.xml");

Categories