Skip to content

RestTemplateBuilder and @RestClientTest in Spring Boot 1.4.0

Spring Boot 1.4.0 is now available. Among the enhancements are new mechanisms to build and test RestTemplates used to make calls to RESTful web services.

RestTemplateBuilder

The new RestTemplateBuilder class allows RestTemplates to be configured by the REST client class. A RestTemplateBuilder  instance is auto-configured by Spring Boot with sensible defaults. Any custom values can be overridden as necessary.

As an example, the Spanners Demo application needs to make REST calls to a HAL enabled RESTful service and so needs the Jackson2HalModule set on the Jackson HttpMessageConverter:

Before:

@Service
public class SpannersService {

    private String rootUri;
    private RestTemplate restTemplate;

    public SpannersService(@Value("${app.service.url.spanners}") String rootUri) {
        
        this.rootUri = rootUri;
        
        ObjectMapper mapper = new ObjectMapper();
        mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        mapper.registerModule(new Jackson2HalModule());

        MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
        converter.setSupportedMediaTypes(MediaType.parseMediaTypes("application/hal+json"));
        converter.setObjectMapper(mapper);
        restTemplate = new RestTemplate(Arrays.asList(converter));
    }

After:

@Service
public class SpannersService {

    private RestTemplate restTemplate;

    public SpannersService(RestTemplateBuilder builder, @Value("${app.service.url.spanners}") String rootUri) {
        ObjectMapper mapper = new ObjectMapper();
        mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
        mapper.registerModule(new Jackson2HalModule());
        
        restTemplate = builder.messageConverters(new MappingJackson2HttpMessageConverter(mapper))
                              .rootUri(rootUri).build();
    }

As the RestTemplateBuilder is already set with sensible defaults by Spring Boot, we’ll often need to do nothing more than this to configure a working RestTemplate:

@Service
public class MyRestClientService {

    private RestTemplate restTemplate;

    public MyRestClientService(RestTemplateBuilder builder) {
        restTemplate = builder.build();
    }

As a bonus, the RestTemplateBuilder allows us to set a rootUri for all calls made using the template. This simplifies the client code from this

public Spanner findOne(Long id) {
    return restTemplate.getForObject(rootUri + "/{0}", Spanner.class, id);
}

to this

public Spanner findOne(Long id) {
    return restTemplate.getForObject("/{0}", Spanner.class, id);
}

Any request string that starts with ‘/’ has the configured root URL prepended.

@RestClientTest

The new @RestClientTest annotation simplifies REST client testing considerably. The MockRestServiceServer allows client side code to be tested against a mock server but setting up the mock has always been a little cumbersome:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {ServiceConfig.class})
public class SpannersServiceTest {

    private static final String SERVICE_URL = "http://example.com/spanners";
 
    @Autowired
    private RestTemplate restTemplate;
    private MockRestServiceServer server;
    private SpannersService service;

    @Before
    public void configureService() {
        server = MockRestServiceServer.createServer(restTemplate);
        service = new SpannersService(SERVICE_URL);
        ReflectionTestUtils.setField(service, "restTemplate", restTemplate);

    }

    @Test
    public void testFindOne() throws Exception {

        server.expect(requestTo(SERVICE_URL + "/1")).andExpect(method(GET))
                .andRespond(withHalJsonResponse("/spanner1GET.txt"));

        Spanner spanner = service.findOne(1l);
        assertSpanner("Belinda", 10, "jones", spanner);
    }

In this pre-1.4.0 example, we test the GET specific item REST service, served by the findOne() method of a JpaRepository (see the previous post on No code REST services for details). Note that we have to describe the Spring context with the @ContextConfiguration annotation so that we can inject the RestTemplate configured in ServiceConfig.class. We then provide the configured RestTemplate to the MockRestServiceServer and to our instance of the service under test (SpannersService).

With the new @RestClientTest annotation in Spring Boot 1.4.0 however, this is simplified greatly:

@RunWith(SpringRunner.class)
@RestClientTest(SpannersService.class)
public class SpannersServiceTest {

    @Autowired
    private MockRestServiceServer server;
    @Autowired
    private SpannersService service;

    @Test
    public void testFindOne() throws Exception {

        server.expect(requestTo("/1")).andExpect(method(GET))
                .andRespond(withHalJsonResponse("/spanner1GET.txt"));

        Spanner spanner = service.findOne(1L);
        assertSpanner("Belinda", 10, "jones", spanner);
    }

The SpringRunner and @RestClientTest  set up the necessary Spring context and take care of dependencies for the SpannersService. We only need to @Autowire the MockRestServiceServer and the service under test (SpannersService) as Spring builds them for us. Note also that the test does not mention the REST service location. As the service root URI was provided to the RestTemplateBuilder in SpannersService , the test needs only verify the ‘query’ part of the URL. That is requestTo(“/1”)  verifies that a request is made to http://<whateverServiceHasBeenConfigued>/1.

The @RestClientTest annotation builds on the configurability provided by the RestTemplateBuilder. The @RestClientTest adds a MockServerRestTemplateCustomizer to the RestTemplateBuilder injected into the class under test and this wires it into the MockRestServiceServer. For this reason, the RestTemplateBuilder must be used in any class tested with @RestClientTest. The @RestClientTest annotation will not work with classes that instantiate their own RestTemplate in the old way.

Spring Boot 1.4.0: Before and after

The full code for these examples is in the Spanners project at GitHub, version 4.3. The RestTemplateBuilder can be seen in the SpannersService class: before and after. The @RestClientTest annotation can be seen in the corresponding SpannersServiceTest: before and after. Note also that the old SpannersService used a RestTemplate configured in ServiceConfig. This functionality was moved into the SpannersService class after Spring Boot 1.4.

 

Published inJava TechnologiesSpring BootTesting

One Comment

Leave a Reply

Your email address will not be published. Required fields are marked *