Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/348.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
无法从START\ u对象标记中反序列化java.util.ArrayList的实例_Java_Spring_Jackson_Jax Rs_Resteasy - Fatal编程技术网

无法从START\ u对象标记中反序列化java.util.ArrayList的实例

无法从START\ u对象标记中反序列化java.util.ArrayList的实例,java,spring,jackson,jax-rs,resteasy,Java,Spring,Jackson,Jax Rs,Resteasy,我正试图发布自定义对象的列表。 请求正文中的JSON如下所示: { "collection": [ { "name": "Test order1", "detail": "ahk ks" }, { "name": "Test order2", "detail": "Fisteku" } ] } 处理请求的服务器端代码:

我正试图发布自定义对象的
列表。
请求正文中的JSON如下所示:

{
    "collection": [
        {
            "name": "Test order1",
            "detail": "ahk ks"
        },
        {
            "name": "Test order2",
            "detail": "Fisteku"
        }
    ]
}
处理请求的服务器端代码:

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();
    }
}
但会引发一个异常:

SEVERE: Failed executing POST /rest/corder
org.jboss.resteasy.spi.ReaderException: org.codehaus.jackson.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)

问题在于JSON—默认情况下,无法将其反序列化为
集合
,因为它实际上不是JSON数组—如下所示:

[
    {
        "name": "Test order1",
        "detail": "ahk ks"
    },
    {
        "name": "Test order2",
        "detail": "Fisteku"
    }
]
由于您没有控制反序列化的确切过程(RestEasy会)-第一个选项是将JSON作为
字符串注入,然后控制反序列化过程:

Collection<COrder> readValues = new ObjectMapper().readValue(
    jsonAsString, new TypeReference<Collection<COrder>>() { }
);
Collection readValues=new ObjectMapper().readValue(
jsonAsString,新类型引用(){}
);
你会失去一点不必自己做这件事的便利,但你会很容易地解决问题

另一个选项——如果您无法更改JSON——将构建一个包装器以适合JSON输入的结构——并使用它而不是
集合


希望这有帮助

这将起作用:

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

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

应该是这样的:

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

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 {
    ...
}

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

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

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

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

在Swagger中,元素被定义为

Test:
 "type": "array",
 "minItems": 1,
 "items": {
   "$ref": "#/definitions/TestNew"
  }
虽然它应该是

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

TestNew
应该是数组类型

与Eugen的答案相关,您可以通过创建包含
集合
作为其成员变量的包装器POJO对象来解决这种特殊情况。这将正确地指导Jackson将实际的
集合
数据放在POJO的成员变量中,并生成您在API请求中寻找的JSON

例如:

public class ApiRequest {

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

   // getters
}
公共类请求{
@JsonProperty(“集合”)
私人收藏;
//吸气剂
}
然后将
COrderRestService.postOrder()
的参数类型设置为新的
APIREST
wrapper POJO,而不是
Collection

Dto response=softConvertValue(jsonData,Dto.class);
公共静态T softConvertValue(对象fromValue,类到ValueType)
{
ObjectMapper objMapper=新的ObjectMapper();
返回objMapper.configure(在未知属性上反序列化feature.FAIL,false)
.convertValue(fromValue、toValueType);
}
同一问题:

com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of `java.util.UUID` out of START_OBJECT token
原因如下:

ResponseEntity<UUID> response = restTemplate.postForEntity("/example/", null, UUID.class);
@JsonFormat(with=JsonFormat.Feature.ACCEPT_SINGLE_VALUE_作为_数组)
私人列表订单;

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


因此,我在JSON文件的开头添加了“[”,在结尾添加了“]”,将其转换为一个对象数组,它工作得非常好,没有任何错误。

这些天我遇到了同样的问题,也许更多的细节可能会对其他人有所帮助

我在寻找RESTAPI的一些安全指南,并与json数组进行了比较。查看链接了解详细信息,但基本上,您应该将它们包装在一个对象中,正如我们在本文问题中已经看到的那样

因此,不是:

  [
    {
      "name": "order1"
    },
    {
      "name": "order2"
    }
  ]
我们最好总是这样做:

  {
    "data": [
      {
        "name": "order1"
      },
      {
        "name": "order2"
      }
    ]
  }
当您执行GET时,这是非常直接的,但是如果您尝试发布/放置相同的json,则可能会给您带来一些麻烦

在我的例子中,我有不止一个GET是一个列表,还有不止一个POST/PUT将接收相同的json

因此,我最终要做的是为列表使用一个非常简单的包装器对象:

public class Wrapper<T> {
  private List<T> data;

  public Wrapper() {}

  public Wrapper(List<T> data) {
    this.data = data;
  }
  public List<T> getData() {
    return data;
  }
  public void setData(List<T> data) {
    this.data = data;
  }
}
反序列化仍然是默认的,只是使用de包装器对象:

@PostMapping("/resource")
public ResponseEntity<Void> setResources(@RequestBody Wrapper<ResourceDTO> wrappedResources) {
  List<ResourceDTO> resources = wrappedResources.getData();
  // your code here
  return ResponseEntity
           .ok()
           .build();
}
@PostMapping(“/resource”)
公共响应属性setResources(@RequestBody wrappedResources){
List resources=wrappedResources.getData();
//你的代码在这里
返回响应性
.ok()
.build();
}
就这样!希望它能帮助别人


注意:使用SpringBoot 1.5.5.RELEASE进行测试。

如上所述,以下操作将解决问题:
mapper.configure(反序列化功能。接受单个值作为数组,true)

但是,在我的例子中,提供程序执行[0..1]或[0..*]序列化,而不是作为一个bug,我无法强制执行修复。另一方面,它不想影响我的所有其他需要严格验证的情况下的严格映射程序

因此,我做了一个令人讨厌的Jackson HACK(通常不应该复制;-),特别是因为我的SingleOrListElement只有几个属性需要修补:

@JsonProperty(value = "SingleOrListElement", access = JsonProperty.Access.WRITE_ONLY)
private Object singleOrListElement; 

public List<SingleOrListElement> patch(Object singleOrListElement) {
  if (singleOrListElement instanceof List) {
    return (ArrayList<SingleOrListElement>) singleOrListElement;
  } else {
    LinkedHashMap map = (LinkedHashMap) singleOrListElement;
    return Collections.singletonList(SingletonList.builder()
                            .property1((String) map.get("p1"))
                            .property2((Integer) map.get("p2"))
                            .build());
  }
@JsonProperty(value=“singleorliselement”,access=JsonProperty.access.WRITE\u ONLY)
公共关系
  {
    "data": [
      {
        "name": "order1"
      },
      {
        "name": "order2"
      }
    ]
  }
public class Wrapper<T> {
  private List<T> data;

  public Wrapper() {}

  public Wrapper(List<T> data) {
    this.data = data;
  }
  public List<T> getData() {
    return data;
  }
  public void setData(List<T> data) {
    this.data = data;
  }
}
@ControllerAdvice
public class JSONResponseWrapper implements ResponseBodyAdvice<Object> {

  @Override
  public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
    return true;
  }

  @Override
  @SuppressWarnings("unchecked")
  public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType, Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest request, ServerHttpResponse response) {
    if (body instanceof List) {
      return new Wrapper<>((List<Object>) body);
    }
    else if (body instanceof Map) {
      return Collections.singletonMap("data", body);
    }  
    return body;
  }
}
  {
    "data": [
      {...}
    ]
  }
@PostMapping("/resource")
public ResponseEntity<Void> setResources(@RequestBody Wrapper<ResourceDTO> wrappedResources) {
  List<ResourceDTO> resources = wrappedResources.getData();
  // your code here
  return ResponseEntity
           .ok()
           .build();
}
@JsonProperty(value = "SingleOrListElement", access = JsonProperty.Access.WRITE_ONLY)
private Object singleOrListElement; 

public List<SingleOrListElement> patch(Object singleOrListElement) {
  if (singleOrListElement instanceof List) {
    return (ArrayList<SingleOrListElement>) singleOrListElement;
  } else {
    LinkedHashMap map = (LinkedHashMap) singleOrListElement;
    return Collections.singletonList(SingletonList.builder()
                            .property1((String) map.get("p1"))
                            .property2((Integer) map.get("p2"))
                            .build());
  }
@RequestBody List<String> ids
{
    "ids": [
        "1234",
        "5678"
     ]
}
["1234", "5678"]