How to push external xml file into spring boot embedded tomcat continer - spring-boot

i have created springboot project which gives fat-jar. i want to push external xml file in runtime into it.i want to place that xml file into spring-boot-tomcat container. tried many ways to do it (#import, --spring.config.location,etc) those ways didn't work out for me.
That xml file is ApplicationInsight.xml, which is used to post telemetry from our application to Azure portal.
Highly appreciate any help.

Based on the GitHJub issue, I think part of the problem is how you are passing JVM parameters, and how you are using "spring.config.location".
I am not familiar with Azure Insights really, but if I understand correctly, it is trying to load the ApplicationInsights.xml file to configure itself, and it's doing this automatically. So you really can't set it up in the WebConfigurerAdapter as I previously suggested because it has already initialized itself before that, correct? I left that part in anyways, but I get that it needs to be loaded sooner so I provided a few additional ways to add the file to the classpath ASAP.
New Stuff
First take a look at this line you had originally posted ala GitHub:
java -jar build/libs/file-gateway.jar --spring.config.location=classpath:/apps/conf/ApplicationInsight.xml
Instead the value should be just a folder path, without "classpath" of "file" prefix. Also, try using '-D' instead of '--'.
java -jar build/libs/file-gateway.jar -Dspring.config.location=/apps/conf/
The property is supposed to either refer to a directory containing auto configuration property files for Spring Boot. It can also work for referring to a specific "application.properties|yml" file.
With that, my previous suggestion may work for you.
Old Suggestion
If you require a unique way for loading resources, you can add a resource handler to your application.
#Configuration
#EnableWebMvc
public class MvcConfig extends WebMvcConfigurerAdapter {
#Value("${telemetry.folder}")
private String telemetryFolder;
#Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry
.addResourceLocations(telemetryFolder);
}
}
And/or you could load it with apache IO:
#Value("${telemetry.file}")
private String telemetryFile;
#Autowired
private ResourceLoader resourceLoader;
public String telemtryXml(){
return org.apache.commons.io.IOUtils.toString(resourceLoader.getResource(telemtryFile).getInputStream());
}
But this will only work if the api you are using doesn't need to be initialized much earlier.
More New Stuff
In your last post on the GitHub issue, you tried this:
java -jar build/libs/file-gateway.jar -applicationinsights.configurationDirectory="/apps/conf/"
Instead, try adding the property as a jvm parameter like this:
java -jar build/libs/file-gateway.jar -Dapplicationinsights.configurationDirectory=/apps/conf/
Notice that I added a capital 'D' character after the, and I removed the quotes from the path.
Other ways to add the file to classpath are.
Add the directory to the JVM classpath.
java -cp "build/libs/file-gateway.jar:/apps/conf/*" your.package.MainSpringBootApplication
This requires that you specify the main class which is (commonly) annotated with '#SpringBootApplication' and contains the main method. You do not execute the jar like before, but you do still add it to the classpath.
Forget about SpringBoot, and go back to your roots as a JEE developer. Add a "context.xml" for your app under the "src/main/resources/META-INF" folder, or "src/main/webapp/META-INF". I prefer the later if I'm building an executable war file, and the former for jars.
Example context.xml:
<?xml version='1.0' encoding='utf-8'?>
<!-- path should be the context-path of you application.
<Context path="/">
<Resources className="org.apache.catalina.webresources.StandardRoot">
<PreResources base="/apps/conf"
className="org.apache.catalina.webresources.DirResourceSet"
internalPath="/"
webAppMount="/WEB-INF/classes"/>
</Resources>
</Context>
You can also use JVM parameters with EL.
So if you execute the jar with this:
java -jar build/libs/file-gateway.jar -Dapplicationinsights.configurationDirectory=/apps/conf/
You could set the resources base with this:
<!--snip -->
<PreResources base="${applicationinsights.configurationDirectory}"
<!--snip -->
Hope that helps:)

Related

override spring-boot property in dependency jar file

I have a spring boot project that depends on one of the 3rd party SDK libraries which contains a YAML file with some google cloud URLs.
I want to override those values within my YAML, this works for most of my project but for some reason no luck with this perticular dependency lib.
The Dependency Code
#ConfigurationProperties("google")
public class GoogleProperties {
String url;
..
..
}
Yaml file application-google-prod.yaml
google:
url: some url.
Say this is in a jar called google-client-sdk-1.0.0
My Code
Yaml file application-myapp-prod.yaml
spring:
profiles:
include: google-prod
google:
url: OVERRIDE url.
So I am expecting that the OVERRIDE url should be used when the code in the lib is invoked, but instead it continues to use some url from jar file's yaml.
any pointers?
EDIT
The SDK contains another class
class with the following annotations in the SDK
#Configuation
#PropertySource({"classpath:application-google-prod.yaml})
I think this is forcing SDK to pick the value from the specific YAML ignoring overridden value in the YAML from my app.
Disclaimer:
A is have no mean reproducing your issue, this is just a suggestion.
Notice the absence of #Configuration on GoogleProperties.
You have to either add #Configuration on the properties class:
(impossible in this case) or add #EnableConfigurationProperties(GoogleProperties.class) on top of the class where you want to use the properties.
E.g: Your main class if you want to use them in all the app.
As mentioned in the docs, you can also use:
#ConfigurationPropertiesScan({ "com.google.SDK", "org.acme.another" }) on top of your main class or any #Configuration class where you need those props.
Note: As explained here, the fact that as of spring-boot 2.2 we didn't need any more #Configuration or #EnableConfigurationProperties for the configuration properties feature is outdated.

spring boot app cannot load bundle properties files

I am building an app that mostly provide REST services, nothing fancy. since my data consumed by the app can have multiple languages I thought about using the bundle files.
I created 3 files, one with the default file name and another two with specific languages. The files created using intellij IDE I am using.
I followed this guide https://www.baeldung.com/java-resourcebundle however on each run I am getting:
MissingResourceException: Can't find bundle for base name tp_app_strings, locale en_US
I tried numerous articles but none of them seems to resolve the issue.
One fun fact is that if I am using the #Value("classpath:tp_app_strings.properties") on a 'Resource' field I am able to get a reference to that file, so it spring is able to find it.
Additional thing that I tried was to create a WEB-INF directory and place the files there (read it in some article) but still no positive affect
The project structure is quite straight forward:
Spring boot version 2.2 running tomcat.
Any suggeestions would be highly appriciated
You can load the .properties file to the application context using #PropertySource annotation instead using #Value to load the .properties file to a org.springframework.core.io.Resource instance.
The usage;
#Configuration
#PropertySource("classpath:tp_app_strings.properties")
public class DefaultProperties {
#Value("${property1.name}") // Access properties in the above file here using SpringEL.
private String prop1;
#Value("${property2.name}")
private String prop2;
}
You wouldn't need java.util.ResourceBundle access properties this way. Use different or same class to load other .properties files as well.
Update 1:
In order to have the functionality of java.util.ResourceBundle, you can't just use org.springframework.core.io.Resource class. This class or non of it sub-classes don't provide functions to access properties by its name java.util.ResourceBundle whatsoever.
However, if you want a functionality like java.util.ResourceBundle, you could implement something custom like this using org.springframework.core.io.Resource;
#Configuration
public class PropertyConfig {
#Value("classpath:tp_app_strings.properties")
private Resource defaultProperties;
#Bean("default-lang")
public java.util.Properties getDefaultProperties() throws IOException {
Properties props = new Properties();
props.load(defaultProperties.getInputStream());
return props;
}
}
Make sure to follow correct naming convention when define the property file as java.util.Properties#load(InputStream) expect that.
Now you can #Autowire and use this java.util.Properties bean wherever you want just like with java.util.ResourceBundle using java.util.Properties#getProperty(String) or its overloaded counterpart.
I think it's problem of you properties file naming convention. use underline "_" for specifying locale of file like
filename_[languageCode]_[regionCode]
[languageCode] and [regionCode] are two letters standard code that [regionCode] section is optional
about code abbrivation standard take a look on this question
in your case change file name to tp_app_strings_en_US.properties

Thymeleaf +Spring Boot can't find files (FileNotFoundException)

This is a bit of a silly and frustrating one:
The #Configuration is taken from a tutorial website or forum and in it a
ServletContextTemplateResolver thymeleafTemplateResolver
is created using the ServletContext provided by spring boot.
When requested, a FileNotFoundException is thrown, despite the file being in the configured resources folder.
How do I get it to find the file / load it from the resources?
For thymeleaf to resolve the classpath resources, you need to configure a ClassLoaderTemplateResolver. (You were using a ServletContextTemplateResolver)
Also check that setPrefix is set to the correct folder, eg. "/thymeleaf/" if your documents are in resources/thymeleaf/ and that setSuffix is set to ".html" (or whatever your preferred file suffix is)
To also serve static content, you can extend WebMvcConfigurer and override addResourceHandlers, to then do e.g.
registry.addResourceHandler("/**").addResourceLocations("classpath:/static/");
assuming a static folder in your resources.
(Spring controllers take precedence here)

Spring Boot 2: Using external Property-Files

I have a executeable jar what I want to configure by properties outside of the jar. What works fine is application.properties, when putting it to config folder close to the jar. But I have a second property-file what seems not to be picked up and I would like to have the best practice for that.
The folder config looks like:
In the config-folder you will find:
Both property-files are also in the src/main/resources folder.
My StartClass looks like:
#SpringBootApplication
#PropertySource("migration-shrink.properties")
public class MigrationShrinkApplication implements CommandLineRunner {}
My bat file looks like:
java -jar migration-shrink-0.0.1-SNAPSHOT.jar -Dspring.config.location=./config/migration-shrink.properties
I wanted to separate Spring-Configuration from Application-Configuration, thats why I have two different property-files.
Thank you!
The #PropertySource annotation is not necessary.
As of Spring Boot 2.0, you can declare additional locations with:
-Dspring.config.additional-location=./config/migration-shrink.properties
Keep in mind that those additional locations are searched before others, so values can be overridden in the other locations.
See the Spring Boot reference documentation.

How to Access Spring Configuration Outside a JAR File

I am new with Spring Boot Development and currently can't move-on on the issue of how to load my spring application configuration outside the jar file.
My existing code looks like this
private ApplicationContext context;
public static void main(String[] args){
SpringApplication.run(SMPPEngine.c1ass);
new SMPPEngine();
}
public SMPPEngine(){
loadConfiguration();
process();
}
private void loadConfiguration(){
context = new ClassPatthlApplicationContext(”application-context.xm1”);
}
What I want to achieve is to have the jar file next to application-context.xml in one directory so that when there are configuration changes,I don't need to recompile my code just to reflect the changes on application-context.xml.
Based on what I've read on the internet, this is possible by using 'file://directory/application.xml' instead of classpath. But my problem on using the later is that when you place your jar and file to other location, I am required to do code change to reflect the new directory which does not solve the problem of getting away from code recompilation.
I hope I made my issue clear, and get an immediately response with you guys :)
Thanks in advance :)
There are many approaches to do this, standard, you can use spring file: prefix for accessing filesystem paths.
but with spring boot, you can specifiy it in application.properties with
spring.config.location propertiy, or you can add it in command line when run the spring boot jar file like
java -jar myproject.jar --spring.config.location=classpath:/default.properties,classpath:/override.properties
But for your codes, actually you do not need to re-create the spring context from the configuration files, but you want get the context instance, you just need to inject it
#Autowired
private ApplicationContext context;
Another approach, if you have the infrastructure. Would be to use Spring Cloud Config. After your Boot application is configured to read from it, they can be modified at anytime without recompilation or restarting.

Resources