Category: spring

Scenario

Spring framework provides mechanism for binding controller method parameters to custom model. Here is a very good article on how to implement custom data binding https://www.baeldung.com/spring-mvc-custom-data-binder During data binding there might be a need to access HTTP request body.

Solution

HTTP request body is hidden in the ModelAndViewContainer object that spring provides to the argument resolver. Here is a code example:

public class MyContextArgumentResolver implements HandlerMethodArgumentResolver {
  @Override
  public boolean supportsParameter(@Nullable MethodParameter methodParameter) {
    return methodParameter != null &&
        methodParameter.getParameterAnnotation(MyContext.class) != null;
  }

  @Override
  public Object resolveArgument(@Nullable MethodParameter methodParameter,
                                ModelAndViewContainer modelAndViewContainer,
                                @Nullable NativeWebRequest nativeWebRequest,

    return toContext(modelAndViewContainer);
  }
                                
  private MyContext toContext(ModelAndViewContainer modelAndViewContainer) {
    if (modelAndViewContainer == null) {
      return MyContext.builder().build();
    }

    MyContext.Builder builder = MyContext.builder();

    modelAndViewContainer.getModel().forEach((k, v) -> {
      if (v instanceof BindingResult) {
        BindingResult result = (BindingResult) v;
        if (result.getTarget() instanceof Map) {
          // plain map
          builder
            .setPropertyOne(((Map<?, ?>) result.getTarget()).get("propertyOne"))
            .setPropertyTwo(((Map<?, ?>) result.getTarget()).get("propertyTwo"));         
        } else if (result.getTarget() instanceof MyRequest) {
          // handle MyRequest request
		  builder
            .setPropertyOne(((MyRequest) result.getTarget()).getpropertyOne())
            .setPropertyTwo(((MyRequest) result.getTarget()).getpropertyTwo());
        }
      }
    });

    return builder.builder();
  }                                
}

All details about setting up method argument resolver are omitted and the focus is on the toContext function that demonstrates how to get request body from ModelAndViewContainer.