START_OBJECT 토큰에서 java.util.ArrayList의 인스턴스를 역화 할 수 없습니다.
List
사용자 지정 개체 를 게시 합니다. 요청 본문의 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();
}
}
법인 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() + "]";
}
}
그러나 예외가 발생합니다.
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입니다. 기본적 이것은 Collection
으로 JSON 배열 이 아니기 때문에 기본적으로 역 직렬화 할 수 없습니다 .
[
{
"name": "Test order1",
"detail": "ahk ks"
},
{
"name": "Test order2",
"detail": "Fisteku"
}
]
Deserialization의 정확한 프로세스를 제어하지 않기 때문에 (RestEasy는 수행합니다) 첫 번째 옵션 은 JSON을 a로 String
한 다음 deserialization 프로세스를 제어하는 것입니다.
Collection<COrder> readValues = new ObjectMapper().readValue(
jsonAsString, new TypeReference<Collection<COrder>>() { }
);
스스로 할 필요가없는 편리함을 잃어 버릴 수 있습니다.
또 다른 옵션 ( JSON을 변경할 수없는 경우)은 JSON 입력 구조에 맞게 래퍼를 구성하고 대신 Collection<COrder>
.
도움이 되었기를 바랍니다.
JSON 문서 대신 아래와 같이 ObjectMapper 객체를 업데이트 할 수 있습니다.
ObjectMapper mapper = new ObjectMapper();
mapper.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);
이것은 작동합니다 :
단일 요소가있는 목록을 JsonNode 가 아닌 JsonArray로 읽 거나 그 반대로 읽으려고 할 때 문제가 발생할 수 있습니다 .
반환 된 목록에 단일 요소가 포함되어 있는지 (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 {
...
}
Eugen의 답변과 관련하여를 Collection<COrder>
멤버 변수로 포함하는 래퍼 POJO 개체를 만들어이 특정 경우를 해결할 수 있습니다 . 이렇게하면 Jackson Collection
이 POJO의 멤버 변수에 실제 데이터 를 배치 하고 API 요청에서 찾고있는 JSON을 생성하도록 올바르게 안내 합니다.
예:
public class ApiRequest {
@JsonProperty("collection")
private Collection<COrder> collection;
// getters
}
그런 다음의 매개 변수 유형을 대신 COrderRestService.postOrder()
새 ApiRequest
래퍼 POJO로 설정합니다 Collection<COrder>
.
Spring 프레임 워크를 사용하여 만든 REST API에서이 문제가 발생했습니다. 응답 JSON을 만들기 위해 @ResponseBody 주석을 추가하면 문제가 해결되었습니다.
일반적으로 JSON 노드를 Java 객체와 매핑하는 데 문제가있을 때이 문제에 직면합니다. 나는 swagger에서 노드가 Type 배열로 정의되고 JSON 객체에 요소가 하나만 있기 때문에 동일한 문제에 직면했습니다. 따라서 시스템은 하나의 요소 목록을 배열에 매핑하는 데 어려움을 겪었습니다.
Swagger에서 요소는 다음과 같이 정의되었습니다.
Test:
"type": "array",
"minItems": 1,
"items": {
"$ref": "#/definitions/TestNew"
}
그래야하지만
Test:
"$ref": "#/definitions/TestNew"
그리고 TestNew
배열 유형이어야합니다.
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);
}
같은 문제 :
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);
내 테스트에서 의도적으로 요청을 null (콘텐츠 POST 없음)으로 설정했습니다. 앞서 언급했듯이 요청에 유효한 JSON이 포함되지 않았기 때문에 OP의 원인이 동일했기 때문에 서버 ( consumes = "application/json"
) 의 제한 인 애플리케이션 / json 요청으로 자동 식별되지 않았습니다 . 유효한 JSON 요청은 다음과 같습니다. 수정 된 것은 명시 적으로 null 본문과 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);
'IT' 카테고리의 다른 글
iPhone에 호스트 파일이 있습니까? (0) | 2020.08.25 |
---|---|
subprocess.Popen과 os.system의 차이점 (0) | 2020.08.25 |
콜 스택은 정확히 어떻게 작동합니까? (0) | 2020.08.25 |
주어진 위도 / 경도 위치에 대한 경계 상자를 계산하는 방법은 무엇입니까? (0) | 2020.08.25 |
PHP에서“do something OR DIE ()”는 작동 작동 중에 있습니까? (0) | 2020.08.25 |