I have an old system (java8 jee7 glassfish5 spring5) that includes ejb and web tiers. I recently moved it to new system (java17 jee10 glassfish7 spring6). After all coding and configuration changes I finally make most of it works, except for propagating jpa validation result to web tier. Here is my coding. In an entity I have
@Entity
public class Student {
...
@NotNull
private String name;
@Max(20)
private int age;
In the old system I have spring's dispatcher-servlet.xml
<bean id="messageSource" class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<property name="basename" value="/WEB-INF/messages" />
</bean>
In the new system I use WebConfig class instead
@Bean
public MessageSource messageSource() {
ReloadableResourceBundleMessageSource source = new ReloadableResourceBundleMessageSource();
source.setBasename("/WEB-INF/messages");
source.setDefaultEncoding("UTF-8");
return source;
}
and added this to the web.xml
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>test.config.WebConfig</param-value>
</init-param>
I've checked that messages.properties is under /WEB-INF/ in the war file, and contains
NotNull.studentForm.name = must not be blank
Max.studentForm.age = must not be older than {value}
typeMismatch.studentForm.age = must be numeric
In the spring controller
@Controller
public class StudentMaint {
....
@RequestMapping(value = "/StudentMaintEdit.htm")
public String edit(@ModelAttribute("studentForm") @Valid StudentForm form,
BindingResult result, Map model, HttpServletRequest request) throws Exception {
if (result.hasErrors()) {
form.setMode("show");
return "StudentMaint";
}
....... (no validation coding here)
studentFacade.edit(student); (no try/catch for any exception here)
The StudentFacade also doesn't have any validation related coding
In StudentForm
@Component
public class StudentForm {
....
@Valid
private String name;
@Valid
private int age;
The only difference between old and new system is the use of config class instead of xml. Other validation related coding have no change at all. In the old system validation error messages are correctly set by controller and showed through the jsp: name will have must not be blank and age will have must be numeric or must be less than or equal to 20 (note: the last one is not from messages.properties). But in the new system, only the first two violations are showed correctly, the last one causes constraints violation exception and shows the stack trace. My understanding is the first two are spring validation at the web tier while the last one is jpa validation at the ejb tier. But somehow in the old system the jpa violation can be propagated to the web tier with the default message must be less than or equal to 20 while in the new system it didn't. What have I missed?
The old system was built with ant library and the new one with maven which may not be relevant. I've also added a catcher in the controller to catch the violation
@ExceptionHandler(ConstraintViolationException.class)
public String handleConstraintViolation(ConstraintViolationException ex,
Model model, HttpServletRequest request) {
Set<ConstraintViolation<?>> violations = ex.getConstraintViolations();
List<String> errors = new ArrayList<>();
for (ConstraintViolation<?> violation : violations) {
ConstraintDescriptor des = violation.getConstraintDescriptor();
Annotation atn = des.getAnnotation();
log.info("atn = " + atn.toString());
log.info("msg = " + violation.getMessage());
errors.add(violation.getMessage());
}
I got
atn = @jakarta.validation.constraints.Max(message="{jakarta.validation.constraints.Max.message}", payload={}, groups={}, value=20L)
msg = must be less than or equal to 20
so I added to messages.properties
jakarta.validation.constraints.Max.message = must be <= {value}
but still doesn't work. Please help.