A few weeks ago we learned to transform the value of a single request parameter into an object, which is passed to our controller method as a method parameter, by using Spring type converters.

Using type converters is a good choice if we want to create “simple” value objects and inject these objects into our controller methods.

However, sometimes we want to inject objects that fulfill these requirements:

  • The injected object has more than one field and the values of these fields must be read from different sources.
  • The injected object is not a form object.
  • The injected object is not read from the request body.

If we want to fulfill these requirements, we must create a custom HandlerMethodArgumentResolver, and this blog post describes how we can do it.

Let’s start by creating a custom HandlerMethodArgumentResolver that can create FooBar objects.

Creating a Custom HandlerMethodArgumentResolver

The FooBar class is a simple class that has two final fields: bar and foo. Its source code looks as follows:

 1public class FooBar {
 2
 3    private final String bar;
 4    private final String foo;
 5
 6    FooBar(String bar, String foo) {
 7        this.bar = bar;
 8        this.foo = foo;
 9    }
10
11    public String getBar() {
12        return bar;
13    }
14
15    public String getFoo() {
16        return foo;
17    }
18}

We can create a custom HandlerMethodArgumentResolver class, which can create FooBar objects, by following these steps:

  1. Implement the HandlerMethodArgumentResolver interface.
  2. Implement the supportsParameter(MethodParameter methodParameter) method. This method must return true if the type of the method parameter is FooBar and false otherwise.
  3. Implement the resolveArgument() method by following these steps:
  4. Get the value of the ‘bar’ request parameter.
  5. Get the value of the ‘foo’ request parameter.
  6. If the ‘bar’ request parameter is not found from the request, use the default value.
  7. If the ‘foo’ request parameter is not found from the request, use the default value.
  8. Create a new FooBar object and return the created object.

The source code of the FooBarHandlerMethodArgumentResolver class looks as follows:

 1import org.springframework.core.MethodParameter;
 2import org.springframework.web.bind.support.WebDataBinderFactory;
 3import org.springframework.web.context.request.NativeWebRequest;
 4import org.springframework.web.method.support.HandlerMethodArgumentResolver;
 5import org.springframework.web.method.support.ModelAndViewContainer;
 6
 7public final class FooBarHandlerMethodArgumentResolver implements HandlerMethodArgumentResolver {
 8
 9    @Override
10    public boolean supportsParameter(MethodParameter methodParameter) {
11        return methodParameter.getParameterType().equals(FooBar.class);
12    }
13
14    @Override
15    public Object resolveArgument(MethodParameter methodParameter,
16                                  ModelAndViewContainer modelAndViewContainer,
17                                  NativeWebRequest nativeWebRequest,
18                                  WebDataBinderFactory webDataBinderFactory) throws Exception {
19        String bar = nativeWebRequest.getParameter("bar");
20        String foo = nativeWebRequest.getParameter("foo");
21
22        if (isNotSet(bar)) {
23            bar = "defaultBar";
24        }
25
26        if (isNotSet(foo)) {
27            foo = "defaultFoo";
28        }
29
30        return new FooBar(bar, foo);
31    }
32
33    private boolean isNotSet(String value) {
34        return value == null;
35    }
36}

The FooBarHandlerMethodArgumentResolver is a simple class that only demonstrates how you can create your own (and probably a lot more complex) method argument resolvers.

Additional Reading:

Before we can use our new HandlerMethodArgumentResolver class, we have to configure the application context of our web application.

Configuring the Application Context of Our Web Application

Before we can inject FooBar objects into our controller methods, we have to register the FooBarHandlerMethodArgumentResolver as a method argument resolver. This section describes how we can configure the application context of our web application that uses either Spring or Spring Boot.

Configuring a Spring Web Application

We can register the FoobarHandlerMethodArgument class as a method argument resolver by making the following changes to the configuration class that configures the web layer of our Spring web application:

  1. Extend the WebMvcConfigurerAdapter class.
  2. Override the addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) method of the WebMvcConfigurerAdapter class.
  3. Register a custom method argument resolver by creating a new FooBarHandlerMethodArgumentResolver object and adding the creating object to the List given as a method parameter.

The source code of the WebMvcContext class looks as follows:

 1import org.springframework.context.annotation.Configuration;
 2import org.springframework.web.method.support.HandlerMethodArgumentResolver;
 3import org.springframework.web.servlet.config.annotation.EnableWebMvc;
 4import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
 5
 6import java.util.List;
 7
 8@Configuration
 9@EnableWebMvc
10class WebMvcContext extends WebMvcConfigurerAdapter {
11
12    @Override
13    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
14        argumentResolvers.add(new FooBarHandlerMethodArgumentResolver());
15    }
16}

Let’s move on and find out how we can configure the application context of our Spring Boot web application.

Configuring a Spring Boot Web Application

We can register the FoobarHandlerMethodArgument class as a method argument resolver by making the following changes to the “application class” of our Spring Boot web application:

  1. Extend the WebMvcConfigurerAdapter class.
  2. Override the addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) method of the WebMvcConfigurerAdapter class.
  3. Register a custom method argument resolver by creating a new FooBarHandlerMethodArgumentResolver object and adding the creating object to the List given as a method parameter.

The source code of the SpringBootExampleApplication class looks as follows:

 1import org.springframework.boot.SpringApplication;
 2import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
 3import org.springframework.context.annotation.ComponentScan;
 4import org.springframework.context.annotation.Configuration;
 5import org.springframework.web.method.support.HandlerMethodArgumentResolver;
 6import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
 7
 8import java.util.List;
 9
10@Configuration
11@EnableAutoConfiguration
12@ComponentScan
13public class SpringBootExampleApplication extends WebMvcConfigurerAdapter {
14
15    @Override
16    public void addArgumentResolvers(List<HandlerMethodArgumentResolver> argumentResolvers) {
17        argumentResolvers.add(new FooBarHandlerMethodArgumentResolver());
18    }
19
20    public static void main(String[] args) {
21        SpringApplication.run(SpringBootExampleApplication.class, args);
22    }
23}

We are done. Let’s find out how we can use our new method argument resolver.

Using the Custom HandlerMethodArgumentResolver

After we have configured the application context of our web application, we can simply add a new FooBar method parameter into our controller method. The source code of our controller class looks as follows:

 1import org.springframework.web.bind.annotation.RequestMapping;
 2import org.springframework.web.bind.annotation.RequestMethod;
 3import org.springframework.web.bind.annotation.RestController;
 4
 5@RestController
 6final class FooBarController {
 7
 8    @RequestMapping(value = "/test", method = RequestMethod.GET)
 9    public void processFooBar(FooBar fooBar) {
10        //Do stuff
11    }
12}

We can now set the information of the FooBar object by setting the values of the following request parameters:

  • The value of the ‘bar’ request parameter is set as the value of the bar field.
  • The value of the ‘foo’ request parameter is set as the value of the foo field.

The following examples demonstrate how we can create new FooBar object, set the values of its bar and foo fields, and inject it into our controller method.

Example 1:

We have to create a FooBar object that fulfills the following requirements:

  • The value of the bar field is ‘bar’.
  • The value of the foo field is ‘foo’.

We can create this object by sending a GET request to the following url: ‘/test?bar=bar&foo=foo’.

Example 2:

If we want to create a FooBar and set the default values into its bar and foo fields, we have to send a GET request to the following url: ‘/test’.

Let’s move on and summarize what we learned from this blog post.

Summary

This blog post has taught us three things:

  • If we want to inject “complex” objects into our controller methods, and these objects aren’t form objects or read from the request body, we should create a custom method argument resolver.
  • We can create a new method argument resolver by implementing the HandlerMethodArgumentResolver interface.
  • Before we can use a custom HandlerMethodArgumentResolver, we have to register it as a method argument resolver.

P.S. You can get the example application of this blog post from Github.