Reputation: 41
I created validation annotation classes such as @IpV4
, @IpV4List
in library packages. These annotations return the key (code) that can be used in the MessageSource
when the validation is violated.
message.properties
files are in the common resource folder, and each module that uses annotations in library package will attempt to specify the path when registering MessageSource
bean.
However, when an annotation raises an exception such as MethodArgumentNotValidException
, MessageSource
does not find any messages with message template (code defined in the annotation).
I have tried most of the methods posted on StackOverFlow related to this issue.
spring.messages.basename=messages/messages, file:/path/to/file
@Configuration
class (without static-location)@Bean
public MessageSource messageSource(){
ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
messageSource.setBasenames("messages/messages", "file:/path/to/file");
// some other settings...
return messageSource;
}
spring.messages.basename=messages/messages, messages/vailidation_messages
spring.resources.static-locations=file:/path/to/parent_of_messages
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("file:/path/to/parent_of_messages")
// some other settings
;
}
I tried many other approaches, but I could not get a message from calling MessageSource.getMessage()
, and ConstraintViolationException
occurred.
The structure of my projects is as follows.
foo-cloud
│
├─ foo-config
│ ├─ resources
│ │ ├─ messages << message properties here
│ │ │ ├─ validation_messages.properties
│ │ │ ├─ validation_messages_en.properties
│ │ │ ├─ validation_messages_ja.properties
│ │ │ └─ validation_messages_ko.properties
│ │ └─ ...
│ └─ ...
├─ foo-auth
├─ ...
├─ foo-gateway
│
├─ foo-resource
│ ├─ ...
│ ├─ foo-application << module to register Bean for MessageSource here
│ └─ ...
│
├─ foo-library
│ ├─ ...
│ └─ util-lib << annotation for validation here
│
└─ foo-web
└─ ...
edited
)spring.messages.basename=messages/messages, messages/validation_messages # <- how to fix?
spring.messages.encoding=UTF-8
# spring.resources.static-locations=file:../../foo-config/resources #not used anymore
import static java.lang.annotation.ElementType.CONSTRUCTOR;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.ElementType.TYPE_USE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import javax.validation.Constraint;
import javax.validation.Payload;
import javax.validation.constraints.NotEmpty;
import javax.validation.constraints.Pattern;
@Documented
@Constraint(validatedBy = {})
@Target({ FIELD, CONSTRUCTOR, PARAMETER, TYPE_USE })
@Retention(RUNTIME)
@Pattern(regexp = IpV4.PATTERN, message = IpV4.NOT_MATCH)
@NotEmpty(message = IpV4.NOT_EMPTY)
public @interface IpV4 {
String PATTERN = "^(([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\.){3}([01]?\\d\\d?|2[0-4]\\d|25[0-5])$";
String NOT_EMPTY = "validation.ip-v4.not_empty";
String NOT_MATCH = "validation.ip-v4.not_match";
String message() default "invalid ip format";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
@ExceptionHandler(MethodArgumentNotValidException.class)
@ResponseBody
@ResponseStatus(HttpStatus.BAD_REQUEST)
public Map<String, String> validationExceptionCaught(
MethodArgumentNotValidException e) {
return Collections.singletonMap("message", messageSource.getMessage(
e.getBindingResult().getFieldError().getDefaultMessage()));
}
/**
* for debugging
*/
@ExceptionHandler(MethodArgumentTypeMismatchException.class)
@ResponseBody
@ResponseStatus(HttpStatus.BAD_REQUEST)
public Map<String, String> validationExceptionCaught(
MethodArgumentTypeMismatchException e) {
return Collections.singletonMap("message", e.getMessage());
}
@ExceptionHandler(ConstraintViolationException.class)
@ResponseBody
@ResponseStatus(HttpStatus.BAD_REQUEST)
public Map<String, String> validationExceptionCaught(
ConstraintViolationException e) {
return Collections.singletonMap("message",
messageSource.getMessage(
e.getConstraintViolations().stream().findFirst()
.map(ConstraintViolation::getMessageTemplate)
.orElse(e.getMessage())));
}
import foo.bar.lib.common.validator.IpV4;
import lombok.Data;
@Data
public class BarRequest {
@IpV4
private String startIp;
@IpV4
private String endIp;
private String description;
}
How can I use external files as resources for MessageSource To share verification messages?
I am afraid that my English skill is not good enough to communicate.
Upvotes: 0
Views: 4151
Reputation: 41
In the end, I solved this problem.
The problem was that the configuration file was twisted or there was a typo in the file path while trying various methods.
I removed all properties related to MessageSource
from the application.properties
file and registered MessageSource
bean in @Configuration
class as the following source.
@Bean
public MessageSource messageSource() {
ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
messageSource.setBasenames("classpath:messages/messages",
"file:D:/foo-cloud/foo-config/resources/messages_validation");
messageSource.setCacheSeconds(600);
messageSource.setUseCodeAsDefaultMessage(true);
messageSource.setDefaultEncoding(StandardCharsets.UTF_8.name());
return messageSource;
}
Thanks to M.Deinum
for helping me.
Upvotes: 2