无法从 START_OBJECT 令牌反序列化 java.util.ArrayList 的实例

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/20837856/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-13 04:42:14  来源:igfitidea点击:

Can not deserialize instance of java.util.ArrayList out of START_OBJECT token

javaspringHymansonjax-rsresteasy

提问by isah

I'm trying to POST a Listof custom objects. My JSON in request body is this:

我正在尝试发布一个List自定义对象。我在请求正文中的 JSON 是这样的:

{
    "collection": [
        {
            "name": "Test order1",
            "detail": "ahk ks"
        },
        {
            "name": "Test order2",
            "detail": "Fisteku"
        }
    ]
}

Server side code that handles the request:

处理请求的服务器端代码:

import java.util.Collection;

import javax.ws.rs.Consumes;
import javax.ws.rs.POST;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
import javax.ws.rs.core.Response;


@Path(value = "/rest/corder")
public class COrderRestService {

    @POST
    @Produces(MediaType.APPLICATION_JSON)
    @Consumes(MediaType.APPLICATION_JSON)
    public Response postOrder(Collection<COrder> orders) {
        StringBuilder stringBuilder = new StringBuilder();
        for (COrder c : orders) {
            stringBuilder.append(c.toString());
        }
        System.out.println(stringBuilder);
        return Response.ok(stringBuilder, MediaType.APPLICATION_JSON).build();
    }
}

Entity COrder:

实体COrder

import javax.xml.bind.annotation.XmlRootElement;

@XmlRootElement
public class COrder {
    String name;
    String detail;

    @Override
    public String toString() {
        return "COrder [name=" + name + ", detail=" + detail
                + ", getClass()=" + getClass() + ", hashCode()=" + hashCode()
                + ", toString()=" + super.toString() + "]";
    }
}

But an exception is thrown:

但是抛出了一个异常:

SEVERE: Failed executing POST /rest/corder
org.jboss.resteasy.spi.ReaderException: org.codehaus.Hymanson.map.JsonMappingException: Can not deserialize instance of java.util.ArrayList out of START_OBJECT token
 at [Source: org.apache.catalina.connector.CoyoteInputStream@6de8c535; line: 1, column: 1]
    at org.jboss.resteasy.core.MessageBodyParameterInjector.inject(MessageBodyParameterInjector.java:183)
    at org.jboss.resteasy.core.MethodInjectorImpl.injectArguments(MethodInjectorImpl.java:88)
    at org.jboss.resteasy.core.MethodInjectorImpl.invoke(MethodInjectorImpl.java:111)
    at org.jboss.resteasy.core.ResourceMethodInvoker.invokeOnTarget(ResourceMethodInvoker.java:280)
    at org.jboss.resteasy.core.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:234)
    at org.jboss.resteasy.core.ResourceMethodInvoker.invoke(ResourceMethodInvoker.java:221)
    at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:356)
    at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:179)
    at org.jboss.resteasy.plugins.server.servlet.ServletContainerDispatcher.service(ServletContainerDispatcher.java:220)
    at org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher.service(HttpServletDispatcher.java:56)
    at org.jboss.resteasy.plugins.server.servlet.HttpServletDispatcher.service(HttpServletDispatcher.java:51)
    at javax.servlet.http.HttpServlet.service(HttpServlet.java:728)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:305)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
    at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:51)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:243)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:210)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:222)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:123)
    at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:502)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:171)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:100)
    at org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:953)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:118)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:408)
    at org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1041)
    at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:603)
    at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:312)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
    at java.lang.Thread.run(Thread.java:724)

采纳答案by Eugen

The problem is the JSON - this cannot, by default, be deserialized into a Collectionbecause it's not actually a JSON Array - that would look like this:

问题是 JSON - 默认情况下,这不能反序列化为 ,Collection因为它实际上不是 JSON 数组 - 看起来像这样:

[
    {
        "name": "Test order1",
        "detail": "ahk ks"
    },
    {
        "name": "Test order2",
        "detail": "Fisteku"
    }
]

Since you're not controlling the exact process of deserialization (RestEasy does) - a first optionwould be to simply inject the JSON as a Stringand then take control of the deserialization process:

由于您没有控制反序列化的确切过程(RestEasy 可以) -第一个选择是简单地将 JSON 作为 a 注入String,然后控制反序列化过程:

Collection<COrder> readValues = new ObjectMapper().readValue(
    jsonAsString, new TypeReference<Collection<COrder>>() { }
);

You would loose a bit of the convenience of not having to do that yourself, but you would easily sort out the problem.

你会失去一些不必自己做的便利,但你会很容易地解决问题。

Another option- if you cannot change the JSON - would be to construct a wrapper to fit the structure of your JSON input - and use that instead of Collection<COrder>.

另一种选择- 如果您无法更改 JSON - 将构造一个包装器以适合您的 JSON 输入的结构 - 并使用它而不是Collection<COrder>.

Hope this helps.

希望这可以帮助。

回答by Naor Bar

This will work:

这将起作用:

The problem may happen when you're trying to read a list with a single element as a JsonArrayrather than a JsonNodeor vice versa.

当您尝试将具有单个元素的列表作为JsonArray而不是JsonNode读取时,可能会出现问题,反之亦然。

Since you can't know for sure if the returned list contains a single element (so the json looks like this {...})or multiple elements (and the json looks like this [{...},{...}])- you'll have to check in runtime the type of the element.

由于您无法确定返回的列表是否包含单个元素(因此 json 看起来像这样{...}或多个元素(并且 json 看起来像这样[{...},{... }])- 您必须在运行时检查元素的类型。

It should look like this:

它应该是这样的:

(Note: in this code sample I'm using com.fasterxml.Hymanson)

(注意:在此代码示例中,我使用的是 com.fasterxml.Hymanson)

String jsonStr = response.readEntity(String.class);
ObjectMapper mapper = new ObjectMapper();
JsonNode rootNode = mapper.readTree(jsonStr);

// Start by checking if this is a list -> the order is important here:                      
if (rootNode instanceof ArrayNode) {
    // Read the json as a list:
    myObjClass[] objects = mapper.readValue(rootNode.toString(), myObjClass[].class);
    ...
} else if (rootNode instanceof JsonNode) {
    // Read the json as a single object:
    myObjClass object = mapper.readValue(rootNode.toString(), myObjClass.class);
    ...
} else {
    ...
}

回答by Salah Atwa

Instead of the JSON document, you can update the ObjectMapper object like below :

您可以更新 ObjectMapper 对象,而不是 JSON 文档,如下所示:

ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);

回答by Do Will

I had this issue on a REST API that was created using Spring framework. Adding a @ResponseBody annotation (to make the response JSON) resolved it.

我在使用 Spring 框架创建的 REST API 上遇到了这个问题。添加 @ResponseBody 注释(以生成响应 JSON)解决了它。

回答by Ambuj Sinha

Normally we face this issue when there is a problem mapping JSON node with that of Java object. I faced the same issue because in the swagger the node was defined as of Type array and the JSON object was having only one element , hence the system was having difficulty in mapping one element list to an array.

通常,当 JSON 节点与 Java 对象的映射出现问题时,我们会遇到这个问题。我遇到了同样的问题,因为在 swagger 中,节点被定义为 Type 数组,而 JSON 对象只有一个 element ,因此系统很难将一个元素列表映射到一个数组。

In Swagger the element was defined as

在 Swagger 中,元素被定义为

Test:
 "type": "array",
 "minItems": 1,
 "items": {
   "$ref": "#/definitions/TestNew"
  }

While it should be

虽然应该是

Test:
    "$ref": "#/definitions/TestNew"

And TestNewshould be of type array

并且TestNew应该是数组类型

回答by Adil B

Related to Eugen's answer, you can solve this particular case by creating a wrapper POJO object that contains a Collection<COrder>as its member variable. This will properly guide Hymanson to place the actual Collectiondata inside the POJO's member variable and produce the JSON you are looking for in the API request.

与 Eugen 的回答相关,您可以通过创建一个包含 aCollection<COrder>作为其成员变量的包装器 POJO 对象来解决这个特殊情况。这将正确引导 Hymanson 将实际Collection数据放入 POJO 的成员变量中,并生成您在 API 请求中查找的 JSON。

Example:

例子:

public class ApiRequest {

   @JsonProperty("collection")
   private Collection<COrder> collection;

   // getters
}

Then set the parameter type of COrderRestService.postOrder()to be your new ApiRequestwrapper POJO instead of Collection<COrder>.

然后将 的参数类型设置为COrderRestService.postOrder()新的 ApiRequest包装器 POJO 而不是Collection<COrder>.

回答by Dipen Chawla

Dto response = softConvertValue(jsonData, Dto.class);


     public static <T> T softConvertValue(Object fromValue, Class<T> toValueType) 
        {
            ObjectMapper objMapper = new ObjectMapper();
            return objMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false)
                    .convertValue(fromValue, toValueType);
        }

回答by Tanel

Same issue:

同样的问题:

com.fasterxml.Hymanson.databind.exc.MismatchedInputException: Cannot deserialize instance of `java.util.UUID` out of START_OBJECT token

What caused it was the following:

导致它的原因如下:

ResponseEntity<UUID> response = restTemplate.postForEntity("/example/", null, UUID.class);

In my test I purposely set the request as null (no content POST). As previously mentioned, the cause for the OP was the same because the request didn't contain a valid JSON, so it couldn't be automatically identified as an application/json request which was the limitation on the server (consumes = "application/json"). A valid JSON request would be. What fixed it was populating an entity with null body and json headers explicitly.

在我的测试中,我特意将请求设置为 null(没有内容 POST)。如前所述,OP 的原因是相同的,因为请求不包含有效的 JSON,因此无法自动将其识别为应用程序/json 请求,这是服务器 ( consumes = "application/json")上的限制。一个有效的 JSON 请求将是。修复它的是显式填充具有空正文和 json 标头的实体。

HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
HttpEntity request = new HttpEntity<>(null, headers);
ResponseEntity<UUID> response = restTemplate.postForEntity("/example/", request, UUID.class);

回答by Suhas Saheer

@JsonFormat(with = JsonFormat.Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY) private List< COrder > orders;

@JsonFormat(with = JsonFormat.Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY) 私有列表< COrder > 订单;

回答by Akshay Chopra

In my case, the error was being shown because when I was reading my JSON file using Hymanson library, my JSON file contained only 1 object. Hence it started with "{" and ended with "}". But while reading it and storing it in a variable, I was storing it in an Array object (As in my case, there could be more than 1 object).

就我而言,显示错误是因为当我使用 Hymanson 库读取我的 JSON 文件时,我的 JSON 文件只包含 1 个对象。因此它以“{”开头,以“}”结尾。但是在读取它并将其存储在变量中时,我将它存储在一个 Array 对象中(就我而言,可能有 1 个以上的对象)。

Hence, I added "[" in the start and "]" in the end of my JSON file to convert it into an array of object and it worked perfectly fine without any error.

因此,我在 JSON 文件的开头添加了“[”,在 JSON 文件的末尾添加了“]”以将其转换为对象数组,并且它运行得非常好,没有任何错误。