Spring Boot:没有从字符串值反序列化的String-argument构造函数/工厂方法

6
我正在尝试使用RestTemplate(Spring Boot)读取来自rest服务的响应:
RestTemplate restTemplate = new RestTemplate();
ResponseEntity<RMSendPropertyResponse> response = restTemplate.exchange("https://url", HttpMethod.POST, entity, RMSendPropertyResponse.class);
RMSendPropertyResponse rmResponse = response.getBody();

但是当响应中存在错误数组时:
{
    "message": "Something failed.",
    "success": false,
    "errors": [
        {
            "error_code": "MND_00026",
            "error_value": "",
            "error_description": "field not present"
        },
        {
            "error_code": "VAL_00039",
            "error_value": "0",
            "error_description": "Wrong field"
        }
    ],
    "warnings": null,
    "request_timestamp": "18-07-2017 11:34:46",
    "response_timestamp": "18-07-2017 11:34:46"
}

我总是遇到这个错误:
2017-07-18 12:29:08.220 WARN 9489 --- [nio-8080-exec-9] .w.s.m.s.DefaultHandlerExceptionResolver : 无法读取HTTP消息: org.springframework.http.converter.HttpMessageNotReadableException: 无法读取文档:不能构造co.easymatch.portals.rightmove.entities.RMError的实例:没有字符串参数构造函数/工厂方法来从字符串值('MND_00026')反序列化. [来源:java.io.PushbackInputStream@77f5bb5f; 行:1,列:532](通过引用链 co.portals.entities.RMSendPropertyResponse["errors"]->java.util.ArrayList[0]); 嵌套异常是com.fasterxml.jackson.databind.JsonMappingException: 无法构造co.portals.entities.RMError的实例:没有字符串参数构造函数/工厂方法可用于从字符串值('MND_00026')反序列化. [来源:java.io.PushbackInputStream@77f5bb5f; 行:1,列:532](通过引用链 co.portals.entities.RMSendPropertyResponse["errors"]->java.util.ArrayList[0])
我的类是…
RMSendPropertyResponse 类:
@JsonIgnoreProperties(ignoreUnknown = true)
public class RMSendPropertyResponse extends RMResponse {
    private RMPropertyResponse property;
    private List<RMWarning> warnings;
    private List<RMError> errors;

    public RMSendPropertyResponse() {
    }

    public RMPropertyResponse getProperty() {
        return property;
    }

    public void setProperty(RMPropertyResponse property) {
        this.property = property;
    }

    public List<RMWarning> getWarnings() {
        return warnings;
    }

    public void setWarnings(List<RMWarning> warnings) {
        this.warnings = warnings;
    }

    public List<RMError> getErrors() {
        return errors;
    }

    public void setErrors(List<RMError> errors) {
        this.errors = errors;
    }
}

RMError类:

@JsonIgnoreProperties(ignoreUnknown = true)
public class RMError {
    private String error_code;
    private String error_description;
    private String error_value;

    public RMError() {
    }

    public String getError_code() {
        return error_code;
    }

    public void setError_code(String error_code) {
        this.error_code = error_code;
    }

    public String getError_description() {
        return error_description;
    }

    public void setError_description(String error_description) {
        this.error_description = error_description;
    }

    public String getError_value() {
        return error_value;
    }

    public void setError_value(String error_value) {
        this.error_value = error_value;
    }
}

我不明白为什么没有一个构造函数/工厂方法可以从字符串值反序列化。

谢谢。

1个回答

1
你的代码对我来说可行。 你使用的spring-boot版本是什么?你是否管理自己的jackson版本?如果是,你使用的版本是什么。 你确定你从调用的外部url获取的响应是你在问题中粘贴的吗? 这是我复制的可行代码:
@RestController
public class MyController {  

 @GetMapping(value = "/read", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity read() {
    RestTemplate restTemplate = new RestTemplate();
    ResponseEntity<RMSendPropertyResponse> response = restTemplate.exchange("http://localhost:8080/", HttpMethod.GET, null, RMSendPropertyResponse.class);
    RMSendPropertyResponse rmResponse = response.getBody();
    return new ResponseEntity<>(rmResponse, HttpStatus.CREATED);

}

@GetMapping(value = "/", produces = MediaType.APPLICATION_JSON_VALUE)
public String get() {
    return "{\n" +
            "    \"message\": \"Something failed.\",\n" +
            "    \"success\": false,\n" +
            "    \"errors\": [\n" +
            "        {\n" +
            "            \"error_code\": \"MND_00026\",\n" +
            "            \"error_value\": \"\",\n" +
            "            \"error_description\": \"field not present\"\n" +
            "        },\n" +
            "        {\n" +
            "            \"error_code\": \"VAL_00039\",\n" +
            "            \"error_value\": \"0\",\n" +
            "            \"error_description\": \"Wrong field\"\n" +
            "        }\n" +
            "    ],\n" +
            "    \"warnings\": null,\n" +
            "    \"request_timestamp\": \"18-07-2017 11:34:46\",\n" +
            "    \"response_timestamp\": \"18-07-2017 11:34:46\"\n" +
            "}";
  }

}

@JsonIgnoreProperties(ignoreUnknown = true)
class RMError {
    private String error_code;
    private String error_description;
    private String error_value;

    public RMError() {
    }

    public String getError_code() {
        return error_code;
    }

    public void setError_code(String error_code) {
        this.error_code = error_code;
    }

    public String getError_description() {
        return error_description;
    }

    public void setError_description(String error_description) {
        this.error_description = error_description;
    }

    public String getError_value() {
        return error_value;
    }

    public void setError_value(String error_value) {
        this.error_value = error_value;
    }
}

@JsonIgnoreProperties(ignoreUnknown = true)
class RMSendPropertyResponse {

    private List<RMError> errors;

    public RMSendPropertyResponse() {
    }

    public List<RMError> getErrors() {
        return errors;
    }

    public void setErrors(List<RMError> errors) {
        this.errors = errors;
    }
}

谢谢!我正在使用Spring Boot 1.4.2。我没有管理jackson版本。Spring Boot正在获取Jackson 2.8.4。如果我使用Postman调用相同的服务,那就是我得到的原始响应。我将尝试像您一样直接传递这个原始答案,看看是否仍然会出现相同的错误。 - dbeja
好的,所以我尝试手动创建响应,就像你一样,并且它有效。可能是因为我在Postman上得到的响应与我在项目上得到的响应不同?您知道调试来自RestTemplate的原始响应的最佳方法吗? - dbeja
好的,找到问题了...我添加了一个拦截器, 当出现错误时,服务默认回复 XML 而不是 JSON。我在标题中强制只接受 JSON,现在就可以正常工作了! - dbeja
1
当我需要调试通过RestTemplate进行的交换时,我使用ClientHttpRequestInterceptor的实现来记录所有请求和响应。很高兴你解决了你的问题。 - Akli REGUIG

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接