Overwrite content of messages_en.properties from an external messages_en.properties - spring-boot

I have a messages_en.properties inside the classpath (src/main/resources) and one outside the jar, in /config folder. But the messages_en.properties(content) in the /config folder doesn't overwrite the content which is inside the classpath, even after adding this tag:
spring.config.location=config/messages_en.properties
Am I going wrong or this is not possible at all in spring boot?
Do note, the application.properties is in the /config folder (externalized configuration).

You're configuring spring.config.location, which is used to provide the location of the external application configuration (externalized configuration).
If you want to refer to an external location you should prefix your path with file:, for example:
spring.config.location=file:config/application.properties
However, when you use a file called messages_en.properties it's more likely that this is the properties file used by a MessageSource (for internationalization/localization) rather than using it as a replacement for your application.properties file.
You can configure an external location for these messages as well, by configuring the spring.messages.* properties, for example:
spring.messages.basename=file:config/messages
You don't have to add the language code (en), because that's the convention used by Spring already for detecting the proper messages file.
Depending on the given language when calling the MessageSource, it will either open messages_en.properties or messages_fr.properties or ... and use messages.properties as a fallback if there is no property found for the provided language.
EDIT: It appears that the MessageSourceAutoConfiguration only kicks in for classpath resources and you need to have a default fallback messages.properties. If you don't have those, it will not work.
However, you can still use those properties and create a MessageSource manually using #ConfigurationProperties:
#Bean
#ConfigurationProperties("spring.messages")
public MessageSource messageSource() {
return new ReloadableResourceBundleMessageSource();
}

Related

Spring Boot application to have separated multiple property files

Coming from Play Framework, a handy feature that has helped to organize the application configurations was to use includes (Link) to spilt the various configurations into multiple .conf files as below.
application.conf Content
include "play-http.conf"
include "play-modules.conf"
include "play-i18n.conf"
include "authentication.conf"
include "hbase.conf"
include "custom-caches.conf"
include "custom-filters.conf"
#Any other root level application configurations
Is there an equivalent to this in Spring Boot .properties files?
From Spring 2.4, we can create multiple properties file for each profiles as below.
application-main1.properties
application-sub1.properties
application-sub2.properties
And then in default application.properties file we can group all sub profiles and activate the main profile
spring.profiles.group.main1=sub1,sub2
spring.profiles.active=main1
I am not sure if we can group sub profiles under default profile. You can try out
spring.profiles.group.default=sub1,sub2
This way you don't need to have another file for main profile.
I use yaml configuration files myself but I think that the configuration is mostly similar. You should take a look at the PropertySourcesPlaceholderConfigurer.
I have defined a PropertySourcesPlaceholderConfigurer bean to use a configuration override file located outside of the jar. Anything that is in the override file will be used instead of the default configuration. Anything that is not in the override file is still retrieved from the default configuration file. I think you can create a similar bean to achieve what you are looking for.
Here's my code:
#Bean
static PropertySourcesPlaceholderConfigurer propertySourcesPlaceholderConfigurer() {
var properties = new PropertySourcesPlaceholderConfigurer();
properties.setLocation(new FileSystemResource("./application.yaml"));
properties.setIgnoreResourceNotFound(true);
return properties;
}
For my use case, I only needed to define one properties location, but it is also possible to specify multiple locations:
...
properties.setLocations(Resource... locations);
...
My requirement was simply achieved using the spring.config.import (Link).
I created multiple property files such as hbase.properties, custom-caches.properties etc. And then in my application.properties imported those additional property files as below.
spring.config.import=hbase.properties,custom-caches.properties
#Any other properties in the application.properties file
Thanks

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

Spring can't find properties file

I tried all ways to find a file and always got this exception:
java.io.FileNotFoundException: class path resource [src/main/resources/sport.properties] cannot be opened because it does not exist
This is my folder structure:
What path in this String is correct? #PropertySource("classpath:/src/main/resources/sport.properties")
What path in this String is correct? #PropertySource("classpath:/src/main/resources/sport.properties")
That is incorrect because you are mixing up two "name spaces".
The string "classpath:/src/main/resources/sport.properties" is a URI.
The "classpath" means you are telling Spring to look on the application's runtime classpath.
But "/src/main/resources/sport.properties" is not a name on the runtime classpath. Rather it is a pathname in the file system relative to the Eclipse project directory.
Since you are using Maven with Eclipse, you need to understand that the resources tree(s) get added to your classpath; i.e. "${MAVEN_PROJECT}/src/main/resources/a/b" becomes "/a/b" on the runtime classpath.
The "${MAVEN_PROJECT}/src/main/resources" directories for all Maven projects that make up your app are added to the classpath in this way.
When unit testing, "${MAVEN_PROJECT}/src/test/resources" directories get added ro the classpath as well.
In short, you should probably use #PropertySource("classpath:/sport.properties")
I would suggest using TestPropertySource as mentioned below for integration tests.
#RunWith(SpringRunner.class)
#ContextConfiguration(locations = "/applicationContext.xml")
#TestPropertySource(locations = "/sport.properties")
#TestPropertySource is a class-level annotation that is used to
configure the locations() of properties files and inlined properties()
to be added to the Environment's set of PropertySources for an
ApplicationContext for integration tests.
Precedence:- Test property sources have higher precedence than those
loaded from the operating system's environment or Java system
properties as well as property sources added by the application
declaratively via #PropertySource or programmatically (e.g., via an
ApplicationContextInitializer or some other means). Thus, test
property sources can be used to selectively override properties
defined in system and application property sources. Furthermore,
inlined properties() have higher precedence than properties loaded
from resource locations().

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 context:property-placeholder not loading properties

I have a Spring config file with one bean. The bean has 2 properties that are populated from a properties file. I am using the following config in my Spring file to copy the values in but it does not seem to be working.
<context:property-placeholder ignore-resource-not-found="true"
system-properties-mode="NEVER"
location="classpath:my.properties"/>
The weird thing is - this has worked before. Can anyone tell me why this would not be successful in copying the properties across?
I know the infomation given is scant. I'll add elaborate if needs be.
Try the classpath*: prefix. And try giving the relative path to the conf file, and make sure it is really on the classpath (note that WEB-INF is not on the classpath - the classpath of a webapp starts at WEB-INf/classes (and lib))

Resources