Invoking REST Endpoints That Return JSON Arrays with Spring RestTemplate

Setting Up the HTTP Client

A customized RestTemplate bean provides fine-graineed control over connection behavior. The configuration below binds a request factory with a timeout setting.

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.SimpleClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;

@Configuration
public class HttpClientConfig {

    @Bean
    public SimpleClientHttpRequestFactory requestFactory() {
        SimpleClientHttpRequestFactory factory = new SimpleClientHttpRequestFactory();
        factory.setConnectTimeout(1000);
        factory.setReadTimeout(3000);
        return factory;
    }

    @Bean
    public RestTemplate restTemplate(SimpleClientHttpRequestFactory requestFactory) {
        return new RestTemplate(requestFactory);
    }
}

Sample Server-Side Controller

Asssume a service exposes a collection of resources at /orders. The hendler produces a plain JSON array.

import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import java.util.ArrayList;
import java.util.List;

@RestController
public class OrderController {

    @GetMapping(value = "/orders", produces = "application/json")
    public List<Order> fetchOrders() {
        List<Order> result = new ArrayList<>();
        for (int i = 0; i < 10; i++) {
            Order item = new Order();
            item.setId(i);
            item.setLabel(String.format("Order-%d", i));
            result.add(item);
        }
        return result;
    }
}

Deserializing the Response

Strategy 1 — Target a Plain Array

Map the response body directly to a Java array, then wrap it in a List.

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;
import java.util.Arrays;
import java.util.List;

@Component
public class ArrayBasedConsumer {

    private static final String BASE_URL = "http://localhost:8080/api/";

    @Autowired
    private RestTemplate restTemplate;

    public List<Order> loadAllOrders() {
        Order[] rawArray = restTemplate.getForObject(
                BASE_URL + "orders", Order[].class
        );
        return Arrays.asList(rawArray);
    }
}

Strategy 2 — Exploit ParameterizedTypeReference

Use exchange with a ParameterizedTypeReference to capture the generic list type directly, avoiding the intermediate array step.

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.HttpMethod;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestTemplate;
import java.util.List;

@Component
public class GenericTypeConsumer {

    private static final String ENDPOINT = "http://localhost:8080/api/orders";

    @Autowired
    private RestTemplate restTemplate;

    public List<Order> retrieveOrders() {
        ParameterizedTypeReference<List<Order>> typeRef = new ParameterizedTypeReference<>() {};
        ResponseEntity<List<Order>> response = restTemplate.exchange(
                ENDPOINT,
                HttpMethod.GET,
                null,
                typeRef
        );
        return response.getBody();
    }
}

Both approaches yield the same result: the full list of Order objects returned by the service. The choice depends on personal preference and whether you need access to response headers or status codes.

Tags: Spring RestTemplate REST JSON deserialization

Posted on Wed, 10 Jun 2026 18:20:25 +0000 by jdh