I've filed so many bugs since 4.M1 came out, I don't know whether y'all are gonna love me or hate me. :-)
I have the following interface and implementation:
@Validated
public interface EmployeeService
{
public void saveEmployee(
@NotNull(message = "{validate.employeeService.saveEmployee}")
@Valid Employee employee
);
public Employee getEmployee(
@Min(value = 1L,
message = "{validate.employeeService.getEmployee.id}") long id
);
@NotNull
public List<Employee> getAllEmployees();
}
@Service
public class DefaultEmployeeService implements EmployeeService
{
@Override
public void saveEmployee(Employee employee)
{
// no-op
}
@Override
public Employee getEmployee(long id)
{
return null;
}
@Override
public List<Employee> getAllEmployees()
{
return null; // to force trigger a validation error
}
}
I then have a simple controller that uses the service:
@Controller
public class EmployeeController
{
@Inject EmployeeService employeeService;
@RequestMapping(value = "/", method = RequestMethod.GET)
public String listEmployees(Map<String, Object> model)
{
model.put("employees", this.employeeService.getAllEmployees());
return "employee/list";
}
}
I defined a MethodValidationPostProcessor, which attaches a MethodValidationInterceptor to my DefaultEmployeeService methods. When I go to the handler method in the browser, I get this error:
This is because LocalValidatorFactoryBean (SpringValidatorAdapter) does not implement forExecutables. Here's what the JavaDoc has to say about that:
Note that Bean Validation 1.1's #forExecutables method isn't supported: We do not expect that method to be called by application code; consider MethodValidationInterceptor instead. If you really need programmatic #forExecutables access, inject this class as a ValidatorFactory and call getValidator() on it, then #forExecutables on the returned native Validator reference instead of directly on this class.
Well, I am using a MethodValidationInterceptor. MethodValidationInterceptor calls forExecutables, so I'm sure you can see the problem here. I managed to work around this by changing my post-processor definition from this:
@Bean
public MethodValidationPostProcessor methodValidationPostProcessor()
{
MethodValidationPostProcessor processor =
new MethodValidationPostProcessor();
processor.setValidator(this.localValidatorFactoryBean());
return processor;
}
To this:
@Bean
public MethodValidationPostProcessor methodValidationPostProcessor()
{
MethodValidationPostProcessor processor =
new MethodValidationPostProcessor();
processor.setValidator(this.localValidatorFactoryBean().getValidator());
return processor;
}
However, this is non-obvious and certainly not documented clearly.
I see no reason for the restriction documented on LocalValidatorFactoryBean regarding forExecutables. There's no reason that SpringValidatorAdapter can't implement this method. If the underlying Validator is BV 1.1, great. If it's not, the call to the method will throw an AbstractMethodError. But it already does that now, just always, even if the Validator is BV 1.1.
Hmmm. This wasn't as easy as I thought it was going to be. forExecutables returns a type that is also new to BV 1.1, so I can't just add a method that isn't @Override but has the same signature and return type. So, the way I see it, we have two options:
Upgrade the library to BV 1.1, implement the method, and then document that the method is not supported and throws AbstractMethodError if you're using BV 1.0 instead of 1.1 (not a huge change from now, but makes configuration more obvious, so I'm for this one).
Update the MethodValidationInterceptor (or would MethodValidationPostProcessor be better?) to detect if its Validator is a SpringValidatorAdapter and get the underlying Validator in that case. This would achieve the simplification of configuration without upgrading to BV 1.1. However, it feels like a hack to me. I'm open to this idea, and will submit a pull request if y'all think it's the best route to take.
Agreed. I had already implemented this in my local repository and verified that it resolved the issue I was seeing. I have now pushed the commit and submitted a pull request.
Nick Williams opened SPR-10644 and commented
I've filed so many bugs since 4.M1 came out, I don't know whether y'all are gonna love me or hate me. :-)
I have the following interface and implementation:
I then have a simple controller that uses the service:
I defined a
MethodValidationPostProcessor
, which attaches aMethodValidationInterceptor
to myDefaultEmployeeService
methods. When I go to the handler method in the browser, I get this error:This is because
LocalValidatorFactoryBean
(SpringValidatorAdapter
) does not implementforExecutables
. Here's what the JavaDoc has to say about that:Well, I am using a
MethodValidationInterceptor
.MethodValidationInterceptor
callsforExecutables
, so I'm sure you can see the problem here. I managed to work around this by changing my post-processor definition from this:To this:
However, this is non-obvious and certainly not documented clearly.
I see no reason for the restriction documented on
LocalValidatorFactoryBean
regardingforExecutables
. There's no reason thatSpringValidatorAdapter
can't implement this method. If the underlyingValidator
is BV 1.1, great. If it's not, the call to the method will throw anAbstractMethodError
. But it already does that now, just always, even if theValidator
is BV 1.1.I'll send in a pull request shortly.
Affects: 4.0 M1
Referenced from: commits 7b2c74b, 8424974
The text was updated successfully, but these errors were encountered: