I have a Spring mvc application with a Controller, Model, Service, and Validation classes. Everything works fine. In developing what I currently have, I stored the validation messages in a messages.properties file -which I registered in a configuration class like this:
#Bean
public MessageSource messageSource() {
final ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
messageSource.setBasename("[package name]/messages/messages");
return messageSource;
}
In the Validator, I add a validation message if the user didn't answer a field such as this:
ValidationUtils.rejectIfEmptyOrWhitespace(errors, "age", "required", new Object[] {"Age"});
In the messages.properties file I have this (above 'age' is the name of the model object, 'required' is the key used to retrieve the message in the messages.properties file):
required = {0} is required.
Ok, again -this all works fine. But what I'd like to do is externalize the messages to a database (basically, these are corporate messages that all applications use).
My question is -how do I get Spring to use the database instead of messages.properties? Or is I do use messages.properties, to only store the message's id (database key) instead of the message itself?
I have a couple ideas of what to do -but no idea how to do either one. I 'think' that the Spring-form tag library ends up performing the work of getting the actual message. Perhaps I could somehow intercept that call? Or maybe somehow change the messageSource to something else rather than defining the messages.properties file.
Anyways, does anyone have any ideas?
You can try Errors.rejectValue(String field, String errorCode, String defaultMessage) method. I too had the same problem. In my case I used ...errors.rejectValue("firstName", "error.firstName", "plz enter ur first name!!.");
This should ideally use the defaultMessage in the scenario where it can't find the error code from message source.
Instead of using a ResourceBundleMessageSource use a custom MessageSource implementation, which back in a DB. Unfortunately Spring itself doesn't have such an implementation, as described in the jira issue: https://jira.springsource.org/browse/SPR-364
But implementing the MessageSource Interface is straightforward, you can even see a sample implementation attached to the jira issue: https://jira.springsource.org/secure/attachment/10261/JdbcMessageSource.java
Related
We use Spring Kafka together with Spring Boot (all latest versions). We switched handling of Kafka messages into #KafkaHandler annotated methods and expected that #Valid/#Validated together with #Payload will ensure payload validation, but that did not happen. This feature is working for #KafkaListener, should it be also working for #KafkaHandler?
#KafkaListener(...)
#Component
public class NotificationListener {
#KafkaHandler
public void handleV1(#Payload #Valid NotificationV1 notification) {
Thank you.
The Validator is not applied in this case because we just don't reach the PayloadMethodArgumentResolver for that purpose.
The target payload for the multi-method #KafkaListener is resolved before we call the method because we definitely need to know which method to call. Such a logic is done in the InvocableHandlerMethod.getMethodArgumentValues():
args[i] = findProvidedArgument(parameter, providedArgs);
if (args[i] != null) {
continue;
}
...
try {
args[i] = this.resolvers.resolveArgument(parameter, message);
}
The Validator functionality is done in those resolvers. The findProvidedArgument() gives us the payload converted before for execution and here we just don't check any annotations on parameters.
We probably need to poll validation logic into the DelegatingInvocableHandler when we have selected a handler and before its invocation...
Feel free to raise a GitHub issue so we don't forget that this is needed to be addressed somehow.
The reason that why #KafkaListener works with #Valid annotation is that it just like a restful controller endpoint, which is the entrance of the service. The team works to add support for validation working on these situations, and it can be found that this validation mechanism is added in 2018.
As for #KafkaHandler, I'm not that familiar with spring-kafka, but if the validation just not work, it just means that the team doesn't add support for this situation. I recommend you to use the Spring Boot Method Validation Feature, which works fine for all spring managed beans and all the standard validation annotations such as #Size. One last thing, be careful about the exception thrown while validation fails.
I am using spring validation to validate the Rest Controller input, I would appreciate if any one can tell me is there a possibility of throwing custom message in case of exception and the custom message should come from database rather than from a properties file.
You can achieve this by setting a custom validation message source on Spring's LocalValidatorFactoryBean.
Your message source needs to implement the MessageSource interface and read its messages from the database.
Reference:
http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/validation/beanvalidation/LocalValidatorFactoryBean.html#setValidationMessageSource-org.springframework.context.MessageSource-
http://docs.spring.io/spring/docs/current/javadoc-api/org/springframework/context/MessageSource.html
I am loading asynchronously (Ajax call to Spring MVC Controller) a free marker template. But i get error message complaining about missing message property.
This is my Spring controller method
#RequestMapping('/messages/{messageId}')
public String conversation(#PathVariable('messageId') Long messageId, ModelMap model) {
//BUILD CONVERSATION MODEL model.put....
"async/conversation"
}
async/conversation.ftl
.....<#spring.message "user.conversation.title"/>.....
I have message properties with
user.conversation.title Conversation
This message is working just fine in other scenario, i think there is some issue loading the template asynchronously.
Solved: I had forgotten to make an import.
<#import "/spring.ftl" as spring/>
I have a JIRA plugin that I'm developing that has a REST service. That service should be able to accept POSTed requests, unmarshall some data and store it. The seemingly suggested way to do this in JIRA is to make use of the Bandana persistence framework. According to this page, I should be able to simply define a setter that Spring should call to give me my Bandana manager.
#Path("/path")
public class SCMService {
private BandanaManager bandanaManager;
// setter called by Spring
public void setBandanaManager(BandanaManager bandanaManager) {
this.bandanaManager = bandanaManager;
}
//...More methods...
}
However, when I test this, the setter is never being called and my manager is null. I'm guessing this should be as simple as registering this service with Spring for injection somehow but I can't seem to find anything like that.
How would I get my setter called? Is there a better way to do this?
Er, I'm not sure that JIRA uses Bandana in that way, though Confluence does. You can certainly post data to a JIRA rest resource and then store it using properties tables
Something like this:
#POST
#Consumes (MediaType.APPLICATION_XML)
public Response createComponentAndIssues(#Context HttpServletRequest request, ...
New Problem:
I register / bind my custom property editor and get an java.lang.IllegalArgumentException - as expected.
The problem: I do not know how to create a custom error message if binding fails.
Any idea?
THX!
#InitBinder( { "playerCreationBean" } )
protected void initBinder( final WebDataBinder binder )
{
binder.registerCustomEditor(Date.class, new DatePropertyEditor());
}
axtavt is right. If you have a message bundle in your application (ie, messages.properties in your classpath, being used by a MessageSource implementation) spring can automatically use the friendly message in the bundle. The message 'typeMismatch' is just one of a number of default messages that are used by the binding framework, depending on the name of the object being bound as well as the property being bound to. You can use a debugger to inspect the errors instances after binding and find which messages are created by default when a binding exception occurs. I've found that the Spring Documentation is a bit lacking when it comes to the default message names that are generated.