[Java] Exception that occurs when response JSON and class mapping fails in RestTemplate

7 minute read

Overview

  • Investigate the exception that occurs when the class that maps to the JSON of HTTP response in RestTemplate does not match

Environment

  • Spring Boot 2.3.1 (Spring Framework 5.2.7 + Jackson Databind 2.11.0)
  • Java 11 (AdoptOpenJDK 11.0.7+10)
  • Gradle 6.5
  • macOS 10.15.5 Catalina

Verification code

File list

├── build.gradle
└── src
    └── main
        └── java
            └── com
                └── example
                    ├── DemoApplication.java
                    └── MyResponse.java

build.gradle

plugins {
  id'org.springframework.boot' version '2.3.1.RELEASE'
  id'io.spring.dependency-management' version '1.0.9.RELEASE'
  id'java'
}

group ='com.example'
version = '0.0.1'
sourceCompatibility = '11'

repositories {
  mavenCentral()
}

dependencies {
  implementation'org.springframework.boot:spring-boot-starter-web'
}

src/main/java/com/example/MyResponse.java

A class that maps JSON.

package com.example;

import java.util.List;

public class MyResponse {

  public String name;
  public List<MyData> list; // Examine the exception when trying to map an unexpected value here

  public static class MyData {
    public String foo;
    public String bar;
  }
}

src/main/java/com/example/DemoApplication.java

package com.example;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.http.RequestEntity;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;

import java.net.URI;
import java.util.List;
import java.util.Map;

@SpringBootApplication
@RestController
public class DemoApplication {

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

  // OK: return JSON
  @GetMapping("/ok")
  public Map ok() {
    return
      Map.of(
        "name", "myname",
        "list", List.of(
          Map.of("foo", "myfoo", "bar", "mybar")
        )
      );
  }

  // NG1: Return JSON that does not match MyResponse
  @GetMapping("/ng1")
  public Map ng1() {
    return
      Map.of(
        "name", "myname",
        "list", "mylist" // the string "mylist" where List should be
      );
  }

  // NG2: Return JSON that does not match MyResponse
  @GetMapping("/ng2")
  public Map ng2() {
    return
      Map.of(
        "name", "myname",
        "list", "" // empty string where List should be
      );
  }

  // NG3: Return JSON that does not match MyResponse
  @GetMapping("/ng3")
  public Map ng3() {
    return
      Map.of(
        "name", "myname",
        "list", List.of("mylist") // The string "mylist" where MyData should be
      );
  }

  // NG4: Return JSON that does not match MyResponse
  @GetMapping("/ng4")
  public Map ng4() {
    return
      Map.of(
        "name", "myname",
        "list", List.of("") // empty string where MyData should be
      );
  }

  @GetMapping("/mydata/{path}")
  public MyResponse mydata(@PathVariable("path") String path) throws Exception {
    try {
      // Get JSON from our server
      String uri = "http://localhost:8080/" + path;
      RequestEntity re = RequestEntity.get(new URI(uri)).build();
      RestTemplate restTemplate = new RestTemplate();

      // convert JSON to MyResponse
      // If the JSON doesn't match MyResponse, an exception is thrown here
      ResponseEntity<MyResponse> res = restTemplate.exchange(re, MyResponse.class);

      return res.getBody();

    } catch (Exception e) {

      // Output what kind of exception is occurring
      System.out.println("Exception class: "+ e.getClass().getName());

      // print the chain of exceptions that caused it
      Throwable cause = e;
      while ((cause = cause.getCause()) != null) (
        System.out.println("Cause exception class: "+ cause.getClass().getName());
      }

      throw e;
    }
  }
}

Start Spring Boot application

$ gradle bootRun
Starting a Gradle Daemon (subsequent builds will be faster)

> Task :bootRun

  .____ _ __ _ _ _
 /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
(( )\___ |'_ |'_| |'_ \/ _` | \ \ \ \
 \\/ ___)| |_)| | | | | || (_| |) ))))
  '|____| .__|_| |_|_| |_\__, | / / / /
 =========|_|==============|___/=/_/_/_/
 :: Spring Boot :: (v2.3.1.RELEASE)

Verification

Make an HTTP request with curl from another console and verify what kind of exception occurs.

OK: JSON that can be mapped to MyResponse

$ curl http://localhost:8080/ok
{"list":[{"foo":"myfoo","bar":"mybar"}],"name":"myname"}
$ curl http://localhost:8080/mydata/ok
{"name":"myname","list":[{"foo":"myfoo","bar":"mybar"}]}

NG1: The string “mylist” where List should be

JSON data to try to map to a class.

$ curl http://localhost:8080/ng1
{"list":"mylist","name":"myname"}

Access the URL that handles the process of mapping JSON data to a class.

$ curl http://localhost:8080/mydata/ng1
{"timestamp":"2020-06-22T21:05:59.317+00:00","status":500,"error":"Internal Server Error","message":"","path":"/ mydata/ng1"}

Spring Boot server side log (partially excerpted and formatted for readability).

Exception class: org.springframework.web.client.RestClientException原因例外クラス: org.springframework.http.converter.HttpMessageNotReadableException
原因例外クラス: com.fasterxml.jackson.databind.exc.MismatchedInputException

2020-06-23 06:05:59.311 ERROR 4196 --- [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.MyResponse] and content type [application/json];

nested exception is org.springframework.http.converter.HttpMessageNotReadableException:
 JSON parse error: Cannot deserialize instance of `java.util.ArrayList<com.example.MyResponse$MyData>` out of VALUE_STRING token;

nested exception is com.fasterxml.jackson.databind.exc.MismatchedInputException:
 Cannot deserialize instance of `java.util.ArrayList<com.example.MyResponse$MyData>` out of VALUE_STRING token
 at [Source: (PushbackInputStream); line: 1, column: 25](throughreferencechain:com.example.MyResponse["list"])] with root cause

Spring Boot サーバ側のログ (出力そのまま)。

例外クラス: org.springframework.web.client.RestClientException
原因例外クラス: org.springframework.http.converter.HttpMessageNotReadableException
原因例外クラス: com.fasterxml.jackson.databind.exc.MismatchedInputException
2020-06-23 06:05:59.311 ERROR 4196 --- [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.MyResponse] and content type [application/json]; nested exception is org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Cannot deserialize instance of `java.util.ArrayList<com.example.MyResponse$MyData>` out of VALUE_STRING token; nested exception is com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of `java.util.ArrayList<com.example.MyResponse$MyData>` out of VALUE_STRING token
 at [Source: (PushbackInputStream); line: 1, column: 25](throughreferencechain:com.example.MyResponse["list"])] with root cause

com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of `java.util.ArrayList<com.example.MyResponse$MyData>` out of VALUE_STRING token
 at [Source: (PushbackInputStream); line: 1, column: 25](throughreferencechain:com.example.MyResponse["list"])
        at com.fasterxml.jackson.databind.exc.MismatchedInputException.from(MismatchedInputException.java:59) ~[jackson-databind-2.11.0.jar:2.11.0]
        at com.fasterxml.jackson.databind.DeserializationContext.reportInputMismatch(DeserializationContext.java:1464) ~[jackson-databind-2.11.0.jar:2.11.0]
        at com.fasterxml.jackson.databind.DeserializationContext.handleUnexpectedToken(DeserializationContext.java:1238) ~[jackson-databind-2.11.0.jar:2.11.0]
        at com.fasterxml.jackson.databind.DeserializationContext.handleUnexpectedToken(DeserializationContext.java:1190) ~[jackson-databind-2.11.0.jar:2.11.0]
        at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.handleNonArray(CollectionDeserializer.java:331) ~[jackson-databind-2.11.0.jar:2.11.0]
        at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:264) ~[jackson-databind-2.11.0.jar:2.11.0]
        at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:244) ~[jackson-databind-2.11.0.jar:2.11.0]
        at com.fasterxml.jackson.databind.deser.std.CollectionDeserializer.deserialize(CollectionDeserializer.java:27) ~[jackson-databind-2.11.0.jar:2.11.0]
        at com.fasterxml.jackson.databind.deser.impl.FieldProperty.deserializeAndSet(FieldProperty.java:138) ~[jackson-databind-2.11.0.jar:2.11.0]
        at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserializeFromObject(BeanDeserializer.java:371) ~[jackson-databind-2.11.0.jar:2.11.0]
        at com.fasterxml.jackson.databind.deser.BeanDeserializer.deserialize(BeanDeserializer.java:164) ~[jackson-databind-2.11.0.jar:2.11.0]
        at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4482) ~[jackson-databind-2.11.0.jar:2.11.0]
        at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3487) ~[jackson-databind-2.11.0.jar:2.11.0]
        at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.readJavaType(AbstractJackson2HttpMessageConverter.java:269) ~[spring-web-5.2.7.RELEASE.jar:5.2.7.RELEASE]
        at org.springframework.http.converter.json.AbstractJackson2HttpMessageConverter.read(AbstractJackson2HttpMessageConverter.java:257) ~[spring-web-5.2.7.RELEASE.jar:5.2.7.RELEASE]at org.springframework.web.client.HttpMessageConverterExtractor.extractData(HttpMessageConverterExtractor.java:105) ~[spring-web-5.2.7.RELEASE.jar:5.2.7.RELEASE]
        at org.springframework.web.client.RestTemplate$ResponseEntityResponseExtractor.extractData(RestTemplate.java:998) ~[spring-web-5.2.7.RELEASE.jar:5.2.7.RELEASE]
        at org.springframework.web.client.RestTemplate$ResponseEntityResponseExtractor.extractData(RestTemplate.java:981) ~[spring-web-5.2.7.RELEASE.jar:5.2.7.RELEASE]
        at org.springframework.web.client.RestTemplate.doExecute(RestTemplate.java:741) ~[spring-web-5.2.7.RELEASE.jar:5.2.7.RELEASE]
        at org.springframework.web.client.RestTemplate.exchange(RestTemplate.java:641) ~[spring-web-5.2.7.RELEASE.jar:5.2.7.RELEASE]
        at com.example.DemoApplication.mydata(DemoApplication.java:86) ~[main/:na]
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:na]
        at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:na]
        at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:na]
        at java.base/java.lang.reflect.Method.invoke(Method.java:566) ~[na:na]
        at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:190) ~[spring-web-5.2.7.RELEASE.jar:5.2.7.RELEASE]
        at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138) ~[spring-web-5.2.7.RELEASE.jar:5.2.7.RELEASE]
        at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:105) ~[spring-webmvc-5.2.7.RELEASE.jar:5.2.7.RELEASE]
        at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:879) ~[spring-webmvc-5.2.7.RELEASE.jar:5.2.7.RELEASE]
        at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:793) ~[spring-webmvc-5.2.7.RELEASE.jar:5.2.7.RELEASE]
        at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) ~[spring-webmvc-5.2.7.RELEASE.jar:5.2.7.RELEASE]
        at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1040) ~[spring-webmvc-5.2.7.RELEASE.jar:5.2.7.RELEASE]
        at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:943) ~[spring-webmvc-5.2.7.RELEASE.jar:5.2.7.RELEASE]
        at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006) ~[spring-webmvc-5.2.7.RELEASE.jar:5.2.7.RELEASE]
        at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898) ~[spring-webmvc-5.2.7.RELEASE.jar:5.2.7.RELEASE]
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:634) ~[tomcat-embed-core-9.0.36.jar:9.0.36]
        at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883) ~[spring-webmvc-5.2.7.RELEASE.jar:5.2.7.RELEASE]
        at javax.servlet.http.HttpServlet.service(HttpServlet.java:741) ~[tomcat-embed-core-9.0.36.jar:9.0.36]
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231) ~[tomcat-embed-core-9.0.36.jar:9.0.36]
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.36.jar:9.0.36]
        at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) ~[tomcat-embed-websocket-9.0.36.jar:9.0.36]
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.36.jar:9.0.36]
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.36.jar:9.0.36]
        at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:100) ~[spring-web-5.2.7.RELEASE.jar:5.2.7.RELEASE]
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.2.7.RELEASE.jar:5.2.7.RELEASE]
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.36.jar:9.0.36]
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.36.jar:9.0.36]
        at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:93) ~[spring-web-5.2.7.RELEASE.jar:5.2.7.RELEASE]
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.2.7.RELEASE.jar:5.2.7.RELEASE]at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.36.jar:9.0.36]
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.36.jar:9.0.36]
        at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:201) ~[spring-web-5.2.7.RELEASE.jar:5.2.7.RELEASE]
        at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:119) ~[spring-web-5.2.7.RELEASE.jar:5.2.7.RELEASE]
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193) ~[tomcat-embed-core-9.0.36.jar:9.0.36]
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166) ~[tomcat-embed-core-9.0.36.jar:9.0.36]
        at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:202) ~[tomcat-embed-core-9.0.36.jar:9.0.36]
        at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96) ~[tomcat-embed-core-9.0.36.jar:9.0.36]
        at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:541) ~[tomcat-embed-core-9.0.36.jar:9.0.36]
        at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139) ~[tomcat-embed-core-9.0.36.jar:9.0.36]
        at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92) ~[tomcat-embed-core-9.0.36.jar:9.0.36]
        at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74) ~[tomcat-embed-core-9.0.36.jar:9.0.36]
        at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343) ~[tomcat-embed-core-9.0.36.jar:9.0.36]
        at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:373) ~[tomcat-embed-core-9.0.36.jar:9.0.36]
        at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:65) ~[tomcat-embed-core-9.0.36.jar:9.0.36]
        at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:868) ~[tomcat-embed-core-9.0.36.jar:9.0.36]
        at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1590) ~[tomcat-embed-core-9.0.36.jar:9.0.36]
        at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) ~[tomcat-embed-core-9.0.36.jar:9.0.36]
        at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) ~[na:na]
        at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) ~[na:na]
        at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) ~[tomcat-embed-core-9.0.36.jar:9.0.36]
        at java.base/java.lang.Thread.run(Thread.java:834) ~[na:na]

NG2: List があるべき場所に空文字列

クラスにマッピング試行する JSON データ。

$ curl http://localhost:8080/ng2
{"list":"","name":"myname"}

JSON データをクラスにマッピングする処理をする URL にアクセス。

$ curl http://localhost:8080/mydata/ng2
{"timestamp":"2020-06-22T21:07:21.986+00:00","status":500,"error":"Internal Server Error","message":"","path":"/mydata/ng2"}

Spring Boot サーバ側のログ (読みやすくするため一部を抜粋して整形したもの)。

例外クラス: org.springframework.web.client.RestClientException
原因例外クラス: org.springframework.http.converter.HttpMessageNotReadableException
原因例外クラス: com.fasterxml.jackson.databind.exc.MismatchedInputException

2020-06-23 06:07:21.984 ERROR 4196 --- [nio-8080-exec-4] 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.MyResponse] and content type [application/json];

nested exception is org.springframework.http.converter.HttpMessageNotReadableException:
 JSON parse error: Cannot construct instance of `java.util.ArrayList` (although at least one Creator exists):
 no String-argument constructor/factory method to deserialize from String value ('');

nested exception is com.fasterxml.jackson.databind.exc.MismatchedInputException:
 Cannot construct instance of `java.util.ArrayList` (although at least one Creator exists):
 no String-argument constructor/factory method to deserialize from String value ('')
 at [Source: (PushbackInputStream); line: 1, column: 25](throughreferencechain:com.example.MyResponse["list"])] with root cause

NG3: MyData があるべき場所に文字列 “mylist”

クラスにマッピング試行する JSON データ。

$ curl http://localhost:8080/ng3
{"list":["mylist"],"name":"myname"}

JSON データをクラスにマッピングする処理をする URL にアクセス。

$ curl http://localhost:8080/mydata/ng3
{"timestamp":"2020-06-22T21:08:08.316+00:00","status":500,"error":"Internal Server Error","message":"","path":"/mydata/ng3"}

Spring Boot サーバ側のログ (読みやすくするため一部を抜粋して整形したもの)。

例外クラス: org.springframework.web.client.RestClientException


原因例外クラス: org.springframework.http.converter.HttpMessageNotReadableException
原因例外クラス: com.fasterxml.jackson.databind.exc.MismatchedInputException

2020-06-23 06:08:08.315 ERROR 4196 --- [nio-8080-exec-6] 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.MyResponse] and content type [application/json];

nested exception is org.springframework.http.converter.HttpMessageNotReadableException:
 JSON parse error: Cannot construct instance of `com.example.MyResponse$MyData` (although at least one Creator exists):
 no String-argument constructor/factory method to deserialize from String value ('mylist');

nested exception is com.fasterxml.jackson.databind.exc.MismatchedInputException:
 Cannot construct instance of `com.example.MyResponse$MyData` (although at least one Creator exists):
 no String-argument constructor/factory method to deserialize from String value ('mylist')
 at [Source: (PushbackInputStream); line: 1, column: 26](throughreferencechain:com.example.MyResponse["list"]->java.util.ArrayList[0])] with root cause

NG4: // MyData があるべき場所に空文字列

クラスにマッピング試行する JSON データ。

$ curl http://localhost:8080/ng4
{"list":[""],"name":"myname"}

JSON データをクラスにマッピングする処理をする URL にアクセス。

$ curl http://localhost:8080/mydata/ng4
{"timestamp":"2020-06-22T21:08:36.354+00:00","status":500,"error":"Internal Server Error","message":"","path":"/mydata/ng4"}

Spring Boot サーバ側のログ (読みやすくするため一部を抜粋して整形したもの)。

例外クラス: org.springframework.web.client.RestClientException
原因例外クラス: org.springframework.http.converter.HttpMessageNotReadableException
原因例外クラス: com.fasterxml.jackson.databind.exc.MismatchedInputException
2020-06-23 06:08:36.352 ERROR 4196 --- [nio-8080-exec-8] 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.MyResponse] and content type [application/json];

nested exception is org.springframework.http.converter.HttpMessageNotReadableException:
 JSON parse error: Cannot construct instance of `com.example.MyResponse$MyData` (although at least one Creator exists):
 no String-argument constructor/factory method to deserialize from String value ('');

nested exception is com.fasterxml.jackson.databind.exc.MismatchedInputException:
 Cannot construct instance of `com.example.MyResponse$MyData` (although at least one Creator exists):
 no String-argument constructor/factory method to deserialize from String value ('')
 at [Source: (PushbackInputStream); line: 1, column: 26](throughreferencechain:com.example.MyResponse["list"]->java.util.ArrayList[0])] with root cause

発生している例外の公式資料

org.springframework.web.client.RestClientException

RestClientException はサーバのエラーレスポンス、入出力エラー、レスポンスをデコードする際のエラーなどで発生する例外。

RestClientException (Spring Framework 5.2.7.RELEASE API)

Base class for exceptions thrown by RestTemplate in case a request fails because of a server error response, as determined via ResponseErrorHandler.hasError(ClientHttpResponse), failure to decode the response, or a low level I/O error.

org.springframework.http.converter.HttpMessageNotReadableException

親クラスの HttpMessageConversionException の説明によると変換に失敗した際に投げられる例外とのこと。

HttpMessageNotReadableException (Spring Framework 5.2.7.RELEASE API)

Thrown by HttpMessageConverter implementations when the HttpMessageConverter.read(java.lang.Class<? extends T>, org.springframework.http.HttpInputMessage) method fails.

HttpMessageConversionException (Spring Framework 5.2.7.RELEASE API)

Thrown by HttpMessageConverter implementations when a conversion attempt fails.

com.fasterxml.jackson.databind.exc.MismatchedInputException

マッピングするクラス定義に合わない JSON が来たときに発生する例外。

MismatchedInputException (jackson-databind 2.11.0 API)

参考資料