Resttemplate getForObject map responsetype

Обновление 02/05/2018 (около 4 лет спустя)... Я проверил это снова, так как люди уже повысили мой вопрос/ответ, и Сотириос Делиманолис прав, что мне не нужно писать код в моем ответьте, чтобы сделать эту работу. Я использовал в основном ту же настройку службы RestTemplate/REST, как показано в моем вопросе, с помощью службы REST, имеющей подтвержденный тип содержимого ответа приложения /json, и RestTemplate смог обработать ответ без проблем на карте.


Я вызываю службу отдыха, которая возвращает JSON следующим образом:

{
   "some.key" : "some value",
   "another.key" : "another value"
}

Мне хотелось бы думать, что я могу вызвать эту службу с помощью java.util.Map в качестве типа ответа, но не работающего для меня. Я получаю это исключение:

org.springframework.web.client.RestClientException: Could not extract response: no suitable HttpMessageConverter found for response type [interface java.util.Map]

Должен ли я просто указать String как тип ответа и преобразовать JSON в Map?

Изменить I

Здесь мой вызов restTemplate:

private Map<String, String> getBuildInfo(String buildUrl) {
    return restTemplate.getForObject(buildUrl, Map.class);
}

Вот как я настраиваю restTemplate:

@PostConstruct
public void initialize() {
    List<ClientHttpRequestInterceptor> interceptors = new ArrayList<>();
    interceptors.add(new ClientHttpRequestInterceptor() {
        @Override
        public ClientHttpResponse intercept(HttpRequest request, byte[] body, ClientHttpRequestExecution execution) throws IOException {
            HttpRequestWrapper requestWrapper = new HttpRequestWrapper(request);
            requestWrapper.getHeaders().setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
            return execution.execute(requestWrapper, body);
        }
    });
    restTemplate.setInterceptors(interceptors);
}

Изменить II

Полное сообщение об ошибке:

org.springframework.web.client.RestClientException: Could not extract response: no suitable HttpMessageConverter found for response type [interface java.util.Map] and content type [application/octet-stream]
    at org.springframework.web.client.HttpMessageConverterExtractor.extractData(HttpMessageConverterExtractor.java:108) ~[spring-web-4.0.3.RELEASE.jar:4.0.3.RELEASE]
    at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:549) ~[spring-web-4.0.3.RELEASE.jar:4.0.3.RELEASE]
    at org.springframework.web.client.RestTemplate.execute(RestTemplate.java:502) ~[spring-web-4.0.3.RELEASE.jar:4.0.3.RELEASE]
    at org.springframework.web.client.RestTemplate.getForObject(RestTemplate.java:239) ~[spring-web-4.0.3.RELEASE.jar:4.0.3.RELEASE]
    at idexx.ordering.services.AwsServersServiceImpl.getBuildInfo(AwsServersServiceImpl.java:96) ~[classes/:na]

Ответ 1

Как я уже отмечал ранее, ваше сообщение об ошибке показывает нам, что вы получаете application/octet-stream как Content-Type.

org.springframework.web.client.RestClientException: Could not extract response: no suitable HttpMessageConverter found for response type [interface java.util.Map] and content type [application/octet-stream]

Таким образом, Jackson MappingJackson2HttpMessageConverter не может анализировать контент (он ожидает application/json).


Оригинальный ответ:

Предполагая, что ваш ответ HTTP Content-Type равен application/json, и у вас есть Jackson 1 или 2 в пути к классам, RestTemplate может десериализовать JSON, как вы, в java.util.Map просто отлично.

С полученной вами ошибкой, которую вы не указали полностью, либо вы зарегистрировали пользовательские объекты HttpMessageConverter, которые перезаписывают значения по умолчанию, либо у вас нет Jackson в вашем пути к классам, а MappingJackson2HttpMessageConverter не регистрируется (что будет делать десериализация), или вы не получаете application/json.

Ответ 2

Обновление 02/05/2018 (около 4 лет спустя)... Я проверил это снова, так как люди уже повысили мой вопрос/ответ, и Сотириос Делиманолис прав, что мне не нужно писать код в моем ответьте, чтобы сделать эту работу. Я использовал в основном ту же настройку службы RestTemplate/REST, как показано в моем вопросе, с помощью службы REST, имеющей подтвержденный тип содержимого ответа приложения /json, и RestTemplate смог обработать ответ без проблем на карте.


В итоге я получил содержимое как String, а затем преобразовал их в Map следующим образом:

String json = restTemplate.getForObject(buildUrl, String.class);
Map<String,String> map = new HashMap<String,String>();
ObjectMapper mapper = new ObjectMapper();

try {
    //convert JSON string to Map
   map = mapper.readValue(json, new TypeReference<HashMap<String,String>>(){});
} catch (Exception e) {
     logger.info("Exception converting {} to map", json, e);
}

return map;

Ответ 3

RestTemplate имеет метод с именем exchange, который принимает экземпляр ParameterizedTypeReference как параметр.

Чтобы сделать запрос GET, который возвращает java.util.Map, просто создайте экземпляр класса анонима, который наследует от ParameterizedTypeReference.

ParameterizedTypeReference<HashMap<String, String>> responseType = 
               new ParameterizedTypeReference<HashMap<String, String>>() {};

Затем вы можете вызвать метод обмена:

RequestEntity<Void> request = RequestEntity.get(URI("http://example.com/foo"))
                 .accept(MediaType.APPLICATION_JSON).build()
Map<String, String> jsonDictionary = restTemplate.exchange(request, responseType)

Ответ 4

Я знаю его старый, но только для других людей, которые могут посетить эту тему: Если вы хотите зарегистрировать некоторые дополнительные конвертеры с помощью RestTemplateBuilder, вам также необходимо явно зарегистрировать значения по умолчанию

@Bean
public RestTemplateBuilder builder() {
    return new RestTemplateBuilder()
            .defaultMessageConverters()
            .additionalMessageConverters(halMessageConverter());
}

private HttpMessageConverter halMessageConverter() {
    ObjectMapper objectMapper = new ObjectMapper().registerModule(new Jackson2HalModule());
    TypeConstrainedMappingJackson2HttpMessageConverter halConverter = new TypeConstrainedMappingJackson2HttpMessageConverter(ResourceSupport.class);
    halConverter.setSupportedMediaTypes(Collections.singletonList(MediaTypes.HAL_JSON));
    halConverter.setObjectMapper(objectMapper);
    return halConverter;
}

Ответ 5

Я думаю, вы можете достичь того, чего хотите, просто используя RestTemplate и указав JsonNode в качестве типа ответа.

    ResponseEntity<JsonNode> response = 
         restTemplate.exchange(url, HttpMethod.GET, entity, JsonNode.class);

    JsonNode map = response.getBody();

    String someValue = map.get("someValue").asText();