how to configure messages property for validation using annotations spring - java

I am using spring-data-rest and I need to configure messages.properties using annotations, What I have done in my configuration class is,
#Bean public ReloadableResourceBundleMessageSource messageSource(){
ReloadableResourceBundleMessageSource reloadableResourceBundleMessageSource = new ReloadableResourceBundleMessageSource();
reloadableResourceBundleMessageSource.setBasename("messages");
return reloadableResourceBundleMessageSource;
}
and tries to access the property in my messages.property file,
notnull.empty=rr is required.
as,
ValidationUtils.rejectIfEmptyOrWhitespace(arg1, "rr", "notnull.empty", "test is required.");
in my Validation Class. But the default message only received and if I remove default message null is received. Is it possible to configure validation messages property file through annotation? Am new to springs, so I cant bet it. Thanks in advance.

The problem is that it is not able to find the message file. It is needed to provide the correct location path to the setBasename method. You can do it in several ways, I will show you two:
1.Using a path from the project root like:
reloadableResourceBundleMessageSource.setBasename("/WEB-INF/messages/messages")‌​;
2.Using a path within the classpath, like:
reloadableResourceBundleMessageSource.setBasename("classpath:/messages/messages")‌​;
I prefer the first because servers use to cache files loaded from the classpath and it makes more difficult to catch changes in the message files.

Related

Spring - yaml and .properties configurations

i've been working with Spring for some time and have a question regarding the very common configuration properties files (like the common application.properties that comes with every spring boot app you initialize). Recently, i also found that configurations like this can be done in yaml files. I have two questions:
When in a application.properties file, we write something like:
# application.properties
spring.debug = true
some-random-value = 15
does this mean that these values will be injected in the application context?
When we write something like:
# application.properties
spring.debug = true
does this mean, that somewhere, there is some class, that has an attribute that looks something like this? -->
#Component
class SomeClass{
#Value("spring.debug")
boolean shouldIRunInDebugMode;
...
}
2.a. If the answer to question 2 is yes, then how can I, looking at something like this:
# application.properties
spring.debug = true
find that class that is expecting that value. The same would apply to if i was looking at something like:
# application.yaml
someThidPartyLibraryName:
shouldWeLog: true
If i see a yaml configuration file, just looking at all the configuration there usually is not enough for me to know what is happening. How can i find the class that is being affected by this configuration, so that i can better understand what this config is doing?
Thank you!
The response is generally yes. If you declare a property in the application.properties or application.yaml is mainly, because you would use it later in the code, for example injecting in some bean with the support of #Value annotation. However, there are also many built-in properties (let's say for example server.port), which you usually don't have to declare and therefore you won't see explicitly in the code. Use an IDE to search the configuration properties and the manual to check the preconfigured ones in case of need.
Your understanding regarding spring value injections from application.properties is correct. #2 - is Yes. Any property from application.properties can be injected to any java class as #Value.
Regarding #2.a - Yaml is just another format on how you organize your variable hierarchy by indentations. That's a superset to the JSON structure.
For example,
in application.properties file you can add something like this
myapp.db.url=<dburl>
myapp.db.username=<dbuser>
myapp.db.password=<dbpassword>
the same can be represented in Yaml in a much efficient manner as below
myapp:
db:
url:<dburl>
username:<dbuser>
password:<dbpassword>
And in either case, for your Jave file you can inject as
#Value("myapp.db.url"
private String dbUrl;
Properties defined in yaml or a properties file may be accessed using the #Value annotation to inject, or using a #ConfigurationProperties class - see https://docs.spring.io/spring-boot/docs/current/reference/html/spring-boot-features.html#boot-features-external-config-typesafe-configuration-properties for complete details.
Finding the property usage is supported by some IDEs - IntelliJ allows you to click through. Otherwise it's a search through the source. For #ConfigurationProperties, once you find the class then just look for code that calls its accessor methods.
Properties files and yaml files are used in Spring Boot for configurations. The main difference between the two is yaml provides structuring/grouping of configurations where as Properties are usually flat and may be repeating the same information:
For example;
Properties file
server.port = 8080
server.host = localhost
yaml file
server:
port: 8080
host: localhost
But in a Spring Boot AutoConfiguration class regardless of yaml or Properties used, a following looking ConfigurationProperties class will be used which will map server.port and server.host
#ConfigurationProperties(prefix = "server")
public class ServerConfiguration {
private int port;
private String host;
}
#Configuration
#EnableConfigurationProperties(ServerConfiguration.class)
public class ServerAutoConfiguration {
}
Hope this answers your questions.

Cannot convert [...ReloadableResourceBundleMessageSource] to required type [...ResourceBundleMessageSource]

So, I try to made my project with internalization. I make
Messages
Messages_en
Messages_fr
If I put them into my /resources/ everything works fine with ResourceBundleMessageSource in my context. But I want to change folder, for example to C:\Apache\servicemix\etc\conf\messages.
And when I made smth like this
Servicemix writes
ResourceBundle [file:C:/Apache/servicemix/etc/conf/messages/Messages] not found for MessageSource: Can't find bundle for base name file:C:/Apache/servicemix/etc/confi/messages/Messages, locale en
In debug mode of Servicemix I`ve tried to get correct Message from my properties and it works when I do something like
ReloadableResourceBundleMessageSource messageSource=new ReloadableResourceBundleMessageSource();
messageSource.setBasename("file:C:/Apache/servicemix/etc/configurator/messages/Messages");
messageSource.getMessage("next",null,new Locale("en"));
I get that I need. I want to use that in my context. But
lead to an error:
Caused by: java.lang.IllegalStateException: Cannot convert value of type [org.springframework.context.support.ReloadableResourceBundleMessageSource] to required type [org.springframework.context.support.ResourceBundleMessageSource] for property 'messageSource': no matching editors or conversion strategy found
at org.springframework.beans.TypeConverterDelegate.convertIfNecessary(TypeConverterDelegate.java:267)
at org.springframework.beans.BeanWrapperImpl.convertIfNecessary(BeanWrapperImpl.java:449)
... 140 more
Why it doesn`t work?
I use clear Spring, not SpringBoot
The error message you get is due to the fact that somewhere in your code base you are using the ResourceBundleMessageSource as a type. Probably in a class which has a field of that type.
Instead of using the concrete type of ResourceBundleMessageSource you should be using the common interface MessageSource instead. This way it doesn't matter which implementation you choose to use.

How to configure the Spring java environment without the locations configuration property?

I am creating a class called FileConfig with the following annotation:
#ConfigurationProperties(locations = { "classpath:application.properties" , "${file.config.location}" })
The following line exists within 'application.properties':
file.config.location = fileinfo.yaml
Apparently, my compiler says, that the locations property has deprecated in favor of configuring the environment directly with additional locations. Can someone please help me how to configure the environment so that the variables in FileConfig are initialized using the contents of 'fileinfo.yaml' file
Using #PropertySource("classpath:testapplication.properties") instead of using the above line of code produces an error.
If I understand your question correctly, you specify the location of fileInfo.yaml file in your application.properties file. And this value should be set as location of your property class FileConfig.
I think thats not possible because SpEL expressions are not evaluated.
Here the part of the java doc from #ConfigurationProperties:
Annotation for externalized configuration. Add this to a class definition or a #Bean method in a #Configuration class if you want to bind and validate some external Properties (e.g. from a .properties file).
Note that contrary to #Value, SpEL expressions are not evaluated since
property values are externalized.

Programmatically accessing camel property from camel context

The project I am working at the moment uses camel as the routing framework.
When configuring camel context in spring we pass a property file that contains a bunch of global properties needed when configuring camel routes or for controlling run time behavior:
<camel:camelContext xmlns="http://camel.apache.org/schema/spring" id="my-id">
<camel:propertyPlaceholder location="my-system.properties" id="global-properties"/>
...
</camel:camelContext>
and say my-system.properties has an entry like below:
my-system.properties
# Global properties that control my-system configuration and run time
...
foo={{bar}}
...
When configuring the routes I can access foo property using the {{foo}} notation. It is also available to other beans using #PropertyInject annotation. However there is one use case in my design when a plain POJO not created by spring (an enum instead but this is not relevant) needs to access my foo property. Because this POJO it is passed the CamelContext as a method argument I find it natural to think I should be able to get the value of foo from there. However I spent a bit of time and could not figure out by myself how.
I know I can load the properties file again or even get the system property System.getProperty("bar") and everything will work but it looks like cheating to me.
There is an api on CamelContext to resolve property placeholders - its the resolvePropertyPlaceholders method:
http://camel.apache.org/maven/current/camel-core/apidocs/org/apache/camel/CamelContext.html#resolvePropertyPlaceholders(java.lang.String)
If your POJO is not being managed by the SpringContext I don't see any way you can automatically inject the property. Although your approach may not seem the most fancy or elegant, it has the advantage of not giving you any overhead you could have by using another injection tool.

Spring Boot default properties encoding change?

I am trying to find a way to set UTF-8 encoding for properties accessed via #Value annotation from application.property files in Spring boot. So far I have been successfully set encoding to my own properties sources by creating a bean:
#Bean
#Primary
public PropertySourcesPlaceholderConfigurer placeholderConfigurer(){
PropertySourcesPlaceholderConfigurer configurer = new PropertySourcesPlaceholderConfigurer();
configurer.setLocation(new ClassPathResource("app.properties");
configurer.setFileEncoding("UTF-8");
return configurer;
}
Such solution presents two problems. For once, it does NOT work with "application.properties" locations used by default by Spring Boot (http://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-external-config.html#boot-features-external-config), and I am forced to use different file names.
And the other problem is, with it I am left with manually defining and ordering supported locations for multiple sources (eg. in jar vs outside jar properties file, etc) thus redoing a job well done already.
How would I obtain a reference to already configured PropertySourcesPlaceholderConfigurer and change it's file encoding at just the right time of application initialization?
Edit:
Perhaps I am doing a mistake somewhere else? This is what causes actual problem for me: When I use application.properties to allow users to apply personal name to emails sent from an application:
#Value("${mail.mailerAddress}")
private String mailerAddress;
#Value("${mail.mailerName}")
private String mailerName; // Actual property is Święty Mikołaj
private InternetAddress getSender(){
InternetAddress sender = new InternetAddress();
sender.setAddress(mailerAddress);
try {
sender.setPersonal(mailerName, "UTF-8"); // Result is Święty Mikołaj
// OR: sender.setPersonal(mailerName); // Result is ??wiÄ?ty Miko??aj
} catch (UnsupportedEncodingException e) {
logger.error("Unsupported encoding used in sender name", e);
}
return sender;
}
When I have placeholderConfigurer bean as shown above added, and place my property inside 'app.properties' it is resoved just fine. Just renaming the file to 'application.properties' breaks it.
Apparently properties loaded by Spring Boot's ConfigFileApplicationListener are encoded in ISO 8859-1 character encoding, which is by design and according to format specification.
On the other hand, the .yaml format supports UTF-8 out of the box. A simple extension change fixes the problem for me.
#JockX suggestion works perfectly. Also, the conversion from property to yaml is quite straightforward.
This:
spring.main.web_environment=false
email.subject.text=Here goes your subject
email.from.name=From Me
email.from.address=me#here.com
email.replyTo.name=To Him
email.replyTo.address=to#him.com
Would become:
spring:
main:
web_environment: false
email:
subject:
text: Here goes your subject
from:
name: From Me
address: me#here.com
replyTo:
name: To Him
address: to#him.com
Another approach would be Instead of renaming the complete file from .properties to .yml you can pick the props which need UTF-8 support and move them to .yml file. This way you need not rewrite ur .properties file.
I advice this because if you have props like
my.string.format= %s-hello-%s
This breaks in .yml files. You would have to write them as
my.string.format: |
%s-hello-%s
Which then leads to adding a new line in the property valye my.string.format when read in the Java code.

Categories