Loading a file as a string content in a Spring service contained in a JAR built with Maven - spring

I am using Spring with Maven and I would like to load a file contained in the maven folder src/main/resources inside a spring service annotated with #Service contained in a JAR file (used by another WAR file as a Maven dependency). This does not seem to work for many different reasons (read: for many different exceptions according to many different attempts).
I know that Maven, when building, puts the stuff in src/main/resources at the root of the JAR file. I've opened the JAR file and I've verified that.
I would prefer a File object (something I can use with utility libraries like Apache Commons IO), but also "something" else that's working is fine.
I would prefere going for stuff within the Java class annotated with #Service (i.e. no application context XML file, with stuff inside that I recall within the service etc.)
The file contains stuff that I eventually use as a List<String> where every item is a line in the original file. I need to keep this file as it is, I can not use a database or another solution different than a file.
This is not a .properties file and is not intended to be.
The following are the not working attempts (throwing NullPointerException, FileNotFoundException, IllegalArgumentException: URI is not hierarchical and so on...).
Among the attempts I have tried also adding/removing the prefix src/main/resources while trying to figure out what was wrong, but then I figured out that Maven puts all the stuff at the root of the JAR file as stated before.
#Value("classpath:src/main/resources/myFile.txt")
private Resource myFileResource;
private File myFile =
new File(this.getClass().getResource("/myFile.txt").toURI());
private File myFile =
new FileSystemResource("src/main/resources/myFile.txt").getFile();
private BufferedReader bufferedReaderMyFile =
new BufferedReader(
new InputStreamReader(getClass().getResourceAsStream("myFile.txt")));
What's wrong with what I am doing?

File inside jar file is no longer a File, so treat it as Resource and read it via Stream
InputStream inputStream = this.getClass().getResourceAsStream("/myFile.txt");
assumming you have actually packed that myFile.txt inside jar file and it is available at the root of JAR file

Related

jar with embedded tomcat, when using another spring project, is not working with just yml - it's needing a blank application.properties file as well

Been searching for others that have run into this issue, and not finding much out there, so it can't be that common.
I have a spring-boot project that I want to convert into a jar project, running with embedded tomcat. It's using yml files (application.yml and then the profile versions - eg appplication-dev.yml.) It ran fine as war with the yml files, however, when I convert it to a jar, and kick off the jar, the embedded tomcat never starts UNLESSS I add an empty application.properties file as well. (No errors just no Tomcat startup unless the empty application.properties file is added.)
I believe it's somehow related to one of our internal jar dependencies (also spring), since if I remove that dependency from the pom (and any of the code referencing it) I can get the jar to startup the embedded tomcat just fine (without providing the empty application.properties file.)
I could also, of course, forgo using yml files and just use .properties files, but I'd like to use yml files if possible. Why adding an empty applcation.properties file causes things to work has me stumped.
If it helps, the config in the dependency project that causes the issue we're seeing is set up as:
#Configuration
#EnableConfigurationProperties(OracleDataSourceProperties.class)
#EnableTransactionManagement
#ComponentScan(basePackages = {"com.foo.data.services","com.foo.data.domain", "com.foo.utility", "com.foo.cipher.utility"})
#MapperScan(value = {"com.foo.data.services.mapper","com.foo.data.services.batchmapper"})
public class DataServicesPersistenceConfig { ... }
and the OracleDataSourceProperties class:
#ConfigurationProperties(prefix="oradb", ignoreUnknownFields = true)
public class OracleDataSourceProperties extends BaseVO implements InitializingBean{

With the spring boot Gradle plugin, is there a task for writing the manifest file without packaging it

I am writing a plug-in using legacy code (on which I don't have any writing rights) for a spring-boot project, and I need to have access to the manifest file in his final form, as produced by the bootJar task. Sadly, this file seems too be directly written to the jar file, without any intermediate file.
Do you know a way to generate the Manifest file in its final form without unzipping the final jar ?
Not sure it helps, and couldn't write it as a comment. I had the same challenge with git, to log the commit id.
build.gradle:
plugins {id 'com.gorylenko.gradle-git-properties'}
gitProperties
project structure:
build
-classes
-generated
-libs
--x.jar
---com
---META-INF
----MANIFEST.MF
---git.properties
src
...
java:
Properties props = new Properties();
InputStream is = getClass().getClassLoader().getResourceAsStream("git.properties");
props.load(is);
log.info("git props: " + props);
so maybe you can try ..getResourceAsStream("META-INF/MANIFEST.MF");
Now I understood you need the access not from the app, but from the plug-in, but still..
Please let us know if you solved the challenge.

How to set file location in application properties - Spring boot

I have a Spring Boot application, the code need to access a file under resources/templates folder.
here is my application.properties file:
pont.email.template.location=templates/mailTemplate.html
This is the java file where I use the variable:
#Value("${pont.email.template.location}")
private String templateLocation;
----------------
BufferedReader reader = new BufferedReader(new FileReader(templateLocation));
The problem is not get the varibale, it returns correctly, The problem is that the application do not found any file for this path.
I always get
java.io.FileNotFoundException: templates/mailTemplate.html (No such file or directory)
I have checked that the file is in the path..
what is wrong in my code?
Help please, thanks.
You cannot read a File from inside a JAR. This fails due to the fact that the File has to point to an actual file resource on the file system and not something inside a JAR.
Let Spring do the heavy lifting and use the Resource abstraction to hide the nasty internals. So instead of using a String use a Resource and prefix the value of the property with classpath: to make sure it is loaded from the classpath. Then use an InputStreamReader instead of FileReader to obtain the information you need.
#Value("${pont.email.template.location}")
private Resource templateLocation;
----------------
BufferedReader reader = new BufferedReader(new InputStreamReader(templateLocation.getInputStream()));
In your application.properties prefix with classpath:.
pont.email.template.location=classpath:templates/mailTemplate.html
Now it should work regardless of the environment you are running in.

Spring Boot on Tomcat set file Paths in properties file

I want to set my relative file path in a properties file so my SaxReader can pick it up when it runs on Tomcat server. I know this should be easy but I've forgotten forgive me :)
I know Spring Boot has application.properties file but I don't see a way to hook in here.
Is there a way to set the relative path in a properties file that will get picked up by Spring Boot and the SaxReader will see it?
As it is I'm hard coding just the filename and putting the file in the resources folder that serves up the templates and static content such as css and js files. The filePath system.out gives: org.dom4j.DocumentException C:sts-bundle\sts-3.7.2.RELEASE\myFileName the toolsuite root location??? weird!!
Please tell me how to specify the relative path in a properties file.
Thanks!!
You can set the file path like any other string property in Spring Boot properties file and access it from inside the path.
E.g. I have the following set in my application.properties file:
download.directory=temp
and it is used as follows in java class:
#Value("${download.directory}")
private String downloadDirectory;
It is used to download the files, now, if I start the application with jar file present in let's say G:/applications folder then the files will be downloaded into G:/applications/temp.

Spring cannot find bean xml configuration file when it does exist

I am trying to make my first bean in Spring but got a problem with loading a context.
I have a configuration XML file of the bean in src/main/resources.
I receive the following IOException:
Exception in thread "main" org.springframework.beans.factory.BeanDefinitionStoreException: IOException parsing XML document from class path resource [src/main/resources/beans.xml]; nested exception is
java.io.FileNotFoundException: class path resource [src/main/resources/beans.xml] cannot
be opened because it does not exist
but I don't get it, since I do the following code test:
File f = new File("src/main/resources/beans.xml");
System.out.println("Exist test: " + f.exists());
which gives me true! resources is in the classpath. What's wrong?
Thanks, but that was not the solution. I found it out why it wasn't working for me.
Since I'd done a declaration:
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
I thought I would refer to root directory of the project when beans.xml file was there.
Then I put the configuration file to src/main/resources and changed initialization to:
ApplicationContext context = new ClassPathXmlApplicationContext("src/main/resources/beans.xml");
it still was an IO Exception.
Then the file was left in src/main/resources/ but I changed declaration to:
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
and it solved the problem - maybe it will be helpful for someone.
Edit:
Since I get many people thumbs up for the solution and had had first experience with Spring as student few years ago, I feel desire to explain shortly why it works.
When the project is being compiled and packaged, all the files and subdirs from 'src/main/java' in the project goes to the root directory of the packaged jar (the artifact we want to create). The same rule applies to 'src/main/resources'.
This is a convention respected by many tools like maven or sbt in process of building project (note: as a default configuration!). When code (from the post) was in running mode, it couldn't find nothing like "src/main/resources/beans.xml" due to the fact, that beans.xml was in the root of jar (copied to /beans.xml in created jar/ear/war).
When using ClassPathXmlApplicationContext, the proper location declaration for beans xml definitions, in this case, was "/beans.xml", since this is path where it belongs in jar and later on in classpath.
It can be verified by unpacking a jar with an archiver (i.e. rar) and see its content with the directories structure.
I would recommend reading articles about classpath as supplementary.
Try this:
new ClassPathXmlApplicationContext("file:src/main/resources/beans.xml");
file: preffix point to file system resources, not classpath.
file path can be relative or system (/home/user/Work/src...)
I also had a similar problem but because of a bit different cause so sharing here in case it can help anybody.
My file location
How I was using
ClassPathXmlApplicationContext("beans.xml");
There are two solutions
Take the beans.xml out of package and put in default package.
Specify package name while using it viz.
ClassPathXmlApplicationContext("com/mypackage/beans.xml");
src/main/resources is a source directory, you should not be referencing it directly. When you build/package the project the contents will be copied into the correct place for your classpath. You should then load it like this
new ClassPathXmlApplicationContext("beans.xml")
Or like this
new GenericXmlApplicationContext("classpath:beans.xml");
This is because applicationContect.xml or any_filename.XML is not placed under proper path.
Trouble shooting Steps
1: Add the XML file under the resource folder.
2: If you don't have a resource folder. Create one by navigating new by Right click on the project new > Source Folder, name it as resource and place your XML file under it.
use it
ApplicationContext context = new FileSystemXmlApplicationContext("Beans.xml");
You have looked at src directory. The xml file indeed exist there. But look at class or bin/build directory where all your output classes are set. I suspect you will need only resources/beans.xml path to use.
I suspect you're building a .war/.jar and consequently it's no longer a file, but a resource within that package. Try ClassLoader.getResourceAsStream(String path) instead.
Note that the first applicationContext is loaded as part of web.xml; which is mentioned with the below.
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>META-INF/spring/applicationContext.xml</param-value>
</context-param>
<servlet>
<servlet-name>myOwn-controller</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>META-INF/spring/applicationContext.xml</param-value>
</init-param>
<load-on-startup>1</load-on-startup>
</servlet>
Where as below code will also tries to create one more applicationContext.
private static final ApplicationContext context =
new ClassPathXmlApplicationContext("beans.xml");
See the difference between beans.xml and applicationContext.xml
And if appliationContext.xml under <META-INF/spring/> has declared with <import resource="beans.xml"/> then this appliationContext.xml is loading the beans.xml under the same location META-INF/spring of appliationContext.xml.
Where as; in the code; if it is declared like below
ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
This is looking the beans.xml at WEB-INF/classes OR in eclipse src/main/resources.
[If you have added beans.xml at src/main/resources then it might be placed at WEB-INF/classes while creating the WAR.]
So totally TWO files are looked up.
I have resolved this issue by adding classpath lookup while importing at applicationContext.xml like below
<import resource="classpath*:beans.xml" />
and removed the the line ClassPathXmlApplicationContext("beans.xml") in java code, so that there will be only one ApplicationContext loaded.
In Spring all source files are inside src/main/java. Similarly, the resources are generally kept inside src/main/resources. So keep your spring configuration file inside resources folder.
Make sure you have the ClassPath entry for your files inside src/main/resources as well.
In .classpath check for the following 2 lines. If they are missing add them.
<classpathentry path="src/main/java" kind="src"/>
<classpathentry path="src/main/resources" kind="src" />
So, if you have everything in place the below code should work.
ApplicationContext ctx = new ClassPathXmlApplicationContext("Spring-Module.xml");
Gradle : v4.10.3
IDE : IntelliJ
I was facing this issue when using gradle to run my build and test. Copying the applicationContext.xml all over the place did not help. Even specifying the complete path as below did not help !
context = new ClassPathXmlApplicationContext("C:\\...\\applicationContext.xml");
The solution (for gradle at least) lies in the way gradle processes resources. For my gradle project I had laid out the workspace as defined at https://docs.gradle.org/current/userguide/java_plugin.html#sec:java_project_layout
When running a test using default gradle set of tasks includes a "processTestResources" step, which looks for test resources at C:\.....\src\test\resources (Gradle helpfully provides the complete path).
Your .properties file and applicationContext.xml need to be in this directory. If the resources directory is not present (as it was in my case), you need to create it copy the file(s) there. After this, simply specifying the file name worked just fine.
context = new ClassPathXmlApplicationContext("applicationContext.xml");
Beans.xml or file.XML is not placed under proper path. You should add the XML file under the resource folder, if you have a Maven project.
src -> main -> java -> resources
I did the opposite of most. I am using Force IDE Luna Java EE and I placed my Beans.xml file within the package; however, I preceded the Beans.xml string - for the ClassPathXMLApplicationContext argument - with the relative path. So in my main application - the one which accesses the Beans.xml file - I have:
ApplicationContext context =
new ClassPathXmlApplicationContext("com/tutorialspoin/Beans.xml");
I also noticed that as soon as I moved the Beans.xml file into the package from the src folder, there was a Bean image at the lower left side of the XML file icon which was not there when this xml file was outside the package. That is a good indicator in letting me know that now the beans xml file is accessible by ClassPathXMLAppllicationsContext.
This is what worked for me:
new ClassPathXmlApplicationContext("classpath:beans.xml");
If this problem is still flummoxing you and you are developing using Eclipse, have a look at this Eclipse bug: Resources files from "src/main/resources" are not correctly included in classpath
Solution seems to be look at properties of project, Java build path, source folders. Delete the /src/main/resources dir and add it again. This causes Eclipse to be reminded it needs to copy these files to the classpath.
This bug affected me when using the "Neon" release of Eclipse. (And was very frustrating until I realized the simple fix just described)
I was experiencing this issue and it was driving me nuts; I ultimately found the following lying in my POM.xml, which was the cause of the problem:
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>true</filtering>
<includes>
<include>**/*.properties</include>
</includes>
</resource>
</resources>
I was not sure to write it but maybe someone save a few hours:
mvn clean
may do the job if your whole configuration is already perfect!
I have stuck in this issue for a while and I have came to the following solution
Create an ApplicationContextAware class (which is a class that implements the ApplicationContextAware)
In ApplicationContextAware we have to implement the one method only
public void setApplicationContext(ApplicationContext context) throws BeansException
Tell the spring context about this new bean (I call it SpringContext)
bean id="springContext" class="packe.of.SpringContext" />
Here is the code snippet
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
public class SpringContext implements ApplicationContextAware {
private static ApplicationContext context;
#Override
public void setApplicationContext(ApplicationContext context) throws BeansException {
this.context = context;
}
public static ApplicationContext getApplicationContext() {
return context;
}
}
Then you can call any method of application context outside the spring context for example
SomeServiceClassOrComponent utilityService SpringContext.getApplicationContext().getBean(SomeServiceClassOrComponent .class);
I hope this will solve the problem for many users
I am on IntelliJ and faced the same issue. Below is how i resolved it:
1. Added the resource import as following in Spring application class along with other imports: #ImportResource("applicationContext.xml")
2. Saw IDE showing : Cannot resolve file 'applicationContext.xml' and also suggesting paths where its expecting the file (It was not the resources where the file applicationContext.xml was originally kept)
3. Copied the file at the expected location and the Exception got resolved.
Screen shot below for easy ref:
But if you would like to keep it at resources then follow this great answer link below and add the resources path so that it gets searched. With this setting exception resolves without #ImportResource described in above steps:
https://stackoverflow.com/a/24843914/5916535
Sharing my case and how I debugged it, maybe helps someone:
this will only be relevant if you have first checked you actually have the resources folder in correct place and correctly named
create some temporary folder somewhere, preferably out of any git projects (e.g. mkdir playground) and move there (cd playground)
copy the java archive there (e.g. cp /path/to/java.war .) that is missing that beans.xml
unpack it (e.g. unzip java.war on ubuntu)
find if there's any .xml files in there (for example in WEB-INF/classes) (the unpacking process should show a list of files being unpacked, most of them will probably be other dependencies as archives, these are not relevant)
if you don't see a beans.xml, just read the other .xml files (e.g. cat root-config.xml), you might find something like root-config.xml there or similar, in there you might either have some other <import resource="somethingelse.xml"> records or nothing.
if this is the case, this means you do have that file (root-config.xml here) present in the project or if not, continue going up parent projects to where the archive is getting packaged from. Find that file, add <import resource="beans.xml"> and run mvn package.
Now verifying the fix by doing the steps in 1.-5. should result in that file (root-config.xml here) in the newly packaged archive having the beans.xml defined and once you deploy it, it should work.
Make sure that beans.xml is located in the resources folder.

Resources