@RestController
class MyController {
@RequestMapping(...)
public void test(Container container) { ... }
}
Spring by default uses Dot-Notation to deserialize a nested @RequestParam:
class Container {
A a;
}
class A {
String val;
}
works with:
http://.../myController?a.val=foo
But for Maps it uses Square Bracket notation:
class Container {
Map<String, String> a;
}
works with:
http://.../myController?a[val]=foo
When using JavaScript there's of course no difference between a HashMap and a Nested Object, so everything will get serialized either with Dots or Square-Brackets.
How / where can I tell Spring (or Spring Boot if that's easier) to use Dot-Notation (or Square Brackets) for both, nested objects and Maps?
Or is there any reason why Spring makes a difference between those types?
Spring Boot supports the use of dot-separated paths to bind maps thanks to its custom DataBinder
subclass, RelaxedDataBinder. The good news is that its also a DataBinder
that's used in Spring MVC to perform the request parameter binding. The bad news is that plugging in your own binder isn't straightforward and that it needs to be a WebDataBinder
. You can plug one in by declaring your own RequestMappingHandlerAdapter
bean named requestMappingHandlerAdapter
. For example:
@Bean
public RequestMappingHandlerAdapter requestMappingHandlerAdpter() {
return new RequestMappingHandlerAdapter() {
@Override
protected InitBinderDataBinderFactory createDataBinderFactory(
List<InvocableHandlerMethod> binderMethods)
throws Exception {
return new ServletRequestDataBinderFactory(binderMethods, getWebBindingInitializer()) {
@Override
protected ServletRequestDataBinder createBinderInstance(
final Object target, String objectName,
NativeWebRequest request) {
return new ServletRequestDataBinder(target) {
private RelaxedDataBinder relaxedBinder = new RelaxedDataBinder(target);
@Override
protected void doBind(MutablePropertyValues mpvs) {
this.relaxedBinder.bind(mpvs);
}
};
}
};
}
};
}
You may well want to refactor this to avoid the use of multiple nested anonymous inner classes, but it hopefully illustrates the general approach.
@InitBinder
private void initBinder(WebDataBinder binder, ServletRequest request) {
new RelaxedDataBinder(binder.getTarget()).bind(new ServletRequestParameterPropertyValues(request));
}
This is how I got away with it; a method in the controller delegating to a RelaxedDataBinder
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With