Home > Enterprise >  RestTemplate::exchange() - com.fasterxml.jackson.core.JsonParseException: Unexpected character (
RestTemplate::exchange() - com.fasterxml.jackson.core.JsonParseException: Unexpected character (

Time:01-08

Getting the following exception while executing a GET against RestTemplate::exchange(). It's a pretty simple public endpoint. I have included the controller and the DTO. The exception notes 'content type [text/html]' - I have read in other articles that this may be related to error response in XML rather than a response JSON. I have looked a little deeper into exception with no success ... again a pretty simple GET endpoint ?? Any help is appreciated.

Public Endpoint

http://catfact.ninja/fact

Exception

2022-01-07 11:18:40.896 ERROR 22564 --- [nio-8080-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in 
context with path [] threw exception [Request processing failed; nested exception 
is org.springframework.web.client.RestClientException: Error while extracting response 
for type [class com.example.demo.CatDTO] and content type [text/html]; nested exception 
is org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Unexpected character ('<' (code 60)): expected a valid value (JSON String, Number, 
Array, Object or token 'null', 'true' or 'false'); nested exception 
is com.fasterxml.jackson.core.JsonParseException: Unexpected character ('<' (code 60)): 
expected a valid value (JSON String, Number, Array, Object or token 'null', 'true' or 'false')
 at [Source: (PushbackInputStream); line: 1, column: 2]] with root cause

DTO Class

public class CatDTO {
    public String fact;
    public int length;
}

Controller Class

package com.example.demo;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.http.*;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.HttpClientErrorException;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.util.UriComponentsBuilder;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;


@RestController
public class CatWebServiceController {
    @Autowired
    RestTemplate restTemplate;

    String url = "http://catfact.ninja/fact";

    @RequestMapping(value = "/cat")
    public ResponseEntity<CatDTO> getCatFact() throws IOException {

        System.out.println("Inside: CatWebServiceController::getCatFact()");

        CatDTO catDTO;

        String urlTemplate = UriComponentsBuilder.fromHttpUrl(url)
                .encode()
                .toUriString();

        // Just a little test
        ObjectMapper mapper = new ObjectMapper();
        File f = new File("C:\\macgowan\\project\\test\\demo\\response.json");
        CatDTO catDTO2 = mapper.readValue(f, CatDTO.class);

        // Create the headers
        HttpHeaders headers = new HttpHeaders();
        headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
        HttpEntity<String> entity = new HttpEntity<String>(headers);

        List<HttpMessageConverter<?>> messageConverters = new ArrayList<HttpMessageConverter<?>>();

        //Add the Jackson Message converter
        MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();

        // Note: here we are making this converter to process any kind of response,
        // not only application/*json, which is the default behaviour
        converter.setSupportedMediaTypes(Collections.singletonList(MediaType.ALL));
        messageConverters.add(converter);
        restTemplate.setMessageConverters(messageConverters);

        ResponseEntity<CatDTO> r = null;

        try
        {
            r = restTemplate.exchange(urlTemplate,
                                      HttpMethod.GET,
                                      entity,
                                      CatDTO.class);
            
            System.out.println("Inside: It worked");
        }
        catch (HttpClientErrorException exc)
        {
            String errorMessage = exc.getResponseBodyAsString();
            System.out.println("Inside: HttpClientErrorException");
        }
        catch (Exception exc)
        {
            String errorMessage = exc.getMessage();
            System.out.println("Inside: Exception");
        }

        return r;
    }
}

Spring Init

package com.example.demo;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.web.client.RestTemplateBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.web.client.RestTemplate;

@SpringBootApplication
public class DemoApplication
{
    public static void main(String[] args)
    {
        SpringApplication.run(DemoApplication.class, args);
    }

    @Bean
    public RestTemplate restTemplate(RestTemplateBuilder builder) {
        return builder.build();
    }
}

CodePudding user response:

Try https://catfact.ninja/fact instead of http://catfact.ninja/fact

What you are receiving is literally:

<html>
<head><title>301 Moved Permanently</title></head>
<body>
<center><h1>301 Moved Permanently</h1></center>
<hr><center>nginx/1.20.1</center>
</body>
</html>

so you where right that your error is related to a response in XML

to quickly find out, you can intercept the response:

 restTemplate.getInterceptors().add((httpRequest, bytes, clientHttpRequestExecution) -> {
            ClientHttpResponse  response=clientHttpRequestExecution.execute(httpRequest, bytes);
            String text = new String(response.getBody().readAllBytes(), StandardCharsets.UTF_8);
            System.out.println(text);
            return response;
        });
  •  Tags:  
  • Related