spring boot loading property file from custom folder - spring-boot

I need to load a property file from src/main/resources/config folder. The loading part is written in a common dependency project where we dont have any control. We are just passing the file name expressed through a dependency. The code snippet in the dependent jar is like below, the standard resource loading.
InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream(propertyFileName);
Spring will always look for recources under recources folder directly, in this case its unable to load the file as its in the custom folder and its not under classpath.
How do we explicitly set the custom folder as additional classpath folder?
With maven we could do something like below which works fine. Is there any OOTB way to achieve this with annotation in spring boot?
`<resources>
<resource>
<directory>src/main/resources</directory>
</resource>
<resource>
<directory>src/main/resources/config</directory>
</resource>
</resources>`
Updated
`// This works if config.properties is directly under resource folder
// What if config.properties is under resources/config folder.
// Dont say to pass argument as /config/config.properties, there are some other limitations.
// So in that case with the same approach, config should come under classpath, so that the below
// method will work always when the property name is passed.
// As mentioned earlier, we can use maven resource settings to achieve this.
// The question here is, is there any way to explicitely advise spring to load property from this folder.
// I have seen something like loader.path config, not sure that helps!
InputStream stream = SpringBootStarter.class.getResourceAsStream("/config.properties");`

Before answering, when you say: Spring will always look for recources under recources folder directly, in this case its unable to load the file as its in the custom folder and its not under classpath., this is not correct.
Spring can look anywhere on your system. Here is how you can load different properties file with Spring and Spring boot:
#PropertySource("classpath:config/common.properties") => Will look under the class path for a file located under the config folder, at the root of your classpath.
#PropertySource("file:/config/common.properties") => Will look for the file common.properties at the root of your filesystem, here under /config/common.properties.
Now, there is the question of "what is the classpath", it seems like it is worth more explanation.
The classpath is for the JVM what the filesystem is for your OS. When you execute some java code (.jar file for instance), the JVM stores all the files you specify. You can specify files when executing java -classpath /a/shared/folder,/a/dependency/app.jar,myApp.jar MainClass. (See this for some others ways: https://javarevisited.blogspot.com/2012/10/5-ways-to-add-multiple-jar-to-classpath-java.html).
Quite often, what happens for developers (before we use Spring) was this:
We develop our application, and use maven for managing the dependencies
We execute our app with the IDE, everything works just as fine, life is wonderful
We are ready to go live (in production). We generate the famous myApp.jar and try executing the application java -jar myApp.jar and... Nothing works. You have issues with java (I assume you setup the main-class in the Manifest...) and you get something like Caused by: java.lang.ClassNotFoundException: my.dependency.OtherClass...
Finally, you realize life is hard and you are not ready to go live right now. You need to have something you can execute easily.
One possible solution to this, to avoid having classpath issues is to put everything in your JAR (called in spring-boot the FAT jar) and you use java -jar myApp.jar and it is working fine.
By default, when you generate a maven project, automatically you have some folders included like:
src/main/java => your java files and packages
src/main/resources => your config files (like .properties)
src/test/java => Your java test files
src/test/resources => the resources handy for your tests
When you generate your jar (more or less every configuration you added to your maven project, but let's say it is okay), what happens is the compiler takes all the folders and files under src/main/java and src/main/resources and put them at the root of your jar. (Don't hesitate to have a look inside your jar files. This is just a Zip, you can open it, browse it, and see for yourself).
With that said, when you say How do we explicitly set the custom folder as additional classpath folder?, and you talk about a custom folder located under src/main/resources, then when you generate your Jar, the custom folder will be in jar, and therefor, in your classpath.
If you still have troubles, this actions will help you:
Unzip your jar files and check what is inside. If you don't see any config/ folder in it, maybe your Jar generation is wrong
Try using #PropertySource(...) to load properties file, in your classpath and in your filesystem, to see how it works and what you achieve
Have also a look to this:
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
Don't hesitate to migrate more and more of your old code to Spring-boot, will be a lot easier for you.

Related

What does Gradle do with the files, which are located in src/main/resources directory?

I'm trying to figure out, what Gradle does with the files, which are located in src/main/resources directory.
The processResources task, added by the java plugin to the project, copies them to the build/resources/main directory.
The content of this directory is bundled into the jar file created by the jar task that is also added by the java plugin, and the resources can thus be loaded, at runtime, by the ClassLoader.
See the documentation of the java plugin.
it might do nothing with them, but ignore them - per default (with the Android plugin) that directory is called res, only the Java plugin would take the resources directory into account (the question does not indicate which plugin is used). otherwise it would run a processResources task on them; only res/raw is not being processed (copied 1:1).

Spring Boot : log4j2.xml next to app.jar not read in production environment

I'm new to Spring Boot.
Under 'resources' there are 2 files :
-- resources
-- application.properties
-- log4j2.xml
In development environment everything works fine.
In production environment, I copy both files and put them next to the app.jar :
-- app_folder
-- my-app.jar
-- application.properties
-- log4j2.xml
When I start the my-app.jar, :
application.properties is read from app_folder, as intended
log4j2.xml is read from 'resources', the one under app_folder is ignored
Shouldn't it work this way out of the box ? What am I doing wrong ?
All I had to do was putting a file named
name-of-my-spring-boot-jar-file.conf
in the same directory as the jar file itself.
Content of conf file :
JAVA_OPTS="-Dlog4j.configurationFile=/home/<user>/log4j2.xml"
Why do you assume it works that way?
It is true that according to its documentation Spring Boot will detect application.properties correctly if it is placed in the same directory as the jar file.
That being said log4j2.xml is not read by Spring Boot but by Log4J2 Framework and according to its documentation that framework oly looks for files on the classpath.
If the file is elsewhere you need to specify the path like this:
java -Dlog4j.configurationFile=path/to/log4j2.xml -jar my-app.jar
Edit:
my-app.jar is an executable, so I don't invoke the 'java' command when starting my-app.
Yes you do. Even if you're invoking it from a GUI (eg. double clicking in Explorer in Windows) it still runs java -jar my-app.jar under the hood.
Isn't the same folder the app.jar resides in considered classpath ?
Again, why would you assume that it is?
In the Java documentation (here for Java 8) in section Folders and Archive Files it clearly says that if the classes are stored in a jar, then the classpath includes only stuff from the jar (although in case of Spring Boot due to the custom classloader it also includes jars embedded in the jar, whch would normally not be the case - see Executable Jar Format).
You really should read the documentation (or at least relevant parts of it) before attempting to use any framework/library/programming language you have not used before - it will save you a lot of time in the long run.

Deploy a embedded Jetty&Jersey war to jetty9,only can see static file?

I cteate a jetty&jersey embedded project with IDEA and Maven,I put it in Github https://github.com/Mengqi777/JettyProject. Run JettyServerStart.java start the server, in the browser address bar enter localhost:8080/dynamic, show OK, enter localhost:8080/static, show static resource file
Now I package it to a war file,and put it in jetty webapps directory. But only can see static file in brower with enter localhost:8080/static.404 Not Found Error when in brower with enter localhost:8080/dynamic
What happend?
What should I do to package this project into a war file or jar file and run it in jetty successfully?
You are doing things in your embedded-jetty usage in JettyServerStart.java that you do not declare/configure in your webapp or war file.
It's a maven project, but not declared as a webapp or war project (in the pom.xml)
Its doesn't have its WEB-INF in the right place (maven directory structure wise), which means your built war file is invalid.
The dependencies are not declared correctly for a webapp or war project (you cannot include jetty-server in a war file)
Your badly located WEB-INF/web.xml does not perform the same configuration steps as your JettyServerStart.java
You don't specify how you created your ${jetty.base} directory to support this war file?
You didn't specify what version of jetty-distribution or jetty-home you downloaded, or are attempting to work with.
The statement "and put it in jetty webapps directory" is unclear, which one? (using jetty-distribution/webapps is invalid and will cause many errors and warnings if you attempt to use it for your own webapps, there's no jetty-home/webapps, and you didn't identify your jetty-base configuration)
The way your project is declared right now, even if manually assembled, skipping maven entirely, you have no servlets, no filters, no listeners, no intializers, only a servlet spec mandated DefaultServlet on url-pattern / giving you static content. That's why accessing http://localhost:8080/static/ works, but nothing else.

How do I add a directory in /target to the resulting JAR with Spring Boot?

I'm using Enunciate to generate REST documentation upon building a REST application. Enunicate outputs documentation to /target/docs. I would like to add the /docs directory to the resulting JAR file (and rename it) to be able to serve docs as static content.
How do I do this? I can't figure out how to get these static files (which are generated upon build) into the JAR.
I guess you can solve this by configuring the Maven plugin for enunciate and wiring it up to be run in the 'generate-resources' lifecycle phase.
Also, make sure you set the output-dir to a subdirectory of src/main/resources/static, as commented by Rob above.
I added this to my enunciate.xml to force the docs directory to be generated in a custom location which will be packaged with the .war file
<docs docsDir="target/<app_name>/docs"/>
and then maven will put the entire contents of target/ into the resulting war file package

Netbeans Including XML and Properties when building Spring projects with Maven

I am new to Maven and Spring. I'm using Netbeans 7 as my IDE, and setting up a Spring 3 project using Maven.
Everything seemed to set up smoothly, and I began running through the Spring User Guide. However, I'm getting a file not found exception when trying to load my context.xml file.
I have an App class located at com.myproject and the context.xml file is located at com.myproject.conf
I'm using the following line of code in App.java to try and load the context.xml file:
ApplicationContext context = new ClassPathXmlApplicationContext("context.xml");
But when I run the application, it results in:
Exception in thread "main" org.springframework.beans.factory.BeanDefinitionStoreException: IOException parsing XML document from class path resource [context.xml]; nested exception is java.io.FileNotFoundException: class path resource [context.xml] cannot be opened because it does not exist
Looking at the NetBeans output, it also looks like it's not picking up the log4j.properties file which is also located in com.myproject.conf
I looked at the jar that the build process created, and the entire com.myproject.conf package is missing, meaning the .xml and .properties are missing as well. I've tried moving these config files to the com.myproject package as well as just putting them at the root of the project which don't yield any different results.
So I'm making the assumption that my maven project isn't set up entirely correctly, or maybe a setting isn't correct within NetBeans.
It seems like you need to learn about resources in Maven projects (such as XML, bitmaps, etc...). These are stored in separate directories. See here.
Put the package in "Other Sources"
I have the same problem with a .property file to manage the Internationalization.
I create it in com.company.app.view.resources at the Source Packages directory.
When I build the project and then look at my war file (target).. I don't found the .property file in /WEB-INF/classes/com/company/app/view/resources
Then I put the package in "Other Sources" directory and it works for me.

Resources