java.util 인스턴스를 역직렬화할 수 없습니다.START_OBJECT 토큰에서 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"
}
]
정확한 역직렬화 프로세스를 제어하고 있지 않기 때문에(RestEasy가 제어한다) 첫 번째 옵션은 단순히 JSON을 인스톨 하는 것입니다.String
다음으로 역직렬화 프로세스를 제어합니다.
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의하여, 당신은 Eugen이 된 포장지 를 만들면 이 할 수 .Collection<COrder>
멤버 변수로 사용합니다.에 의해, 의 「Discounting」을 할 수 .Collection
POJO의 멤버 변수 내의 데이터와 API 요청에서 찾고 있는 JSON을 생성합니다.
예제:
public class ApiRequest {
@JsonProperty("collection")
private Collection<COrder> collection;
// getters
}
다음 매개 .COrderRestService.postOrder()
이 되다ApiRequest
「가 아닌 「Collection<COrder>
.
와 같이 다음과 를 해결할 수 .mapper.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);
단, 이 경우 프로바이더는 [0..1]또는 [0..]를 실행했습니다.*] 시리얼라이제이션은 버그로 인한 것이 아니라 수정을 강제할 수 없었습니다.한편, 엄격하게 검증할 필요가 있는 다른 모든 케이스에 대해서는, 나의 엄격한 맵퍼에 영향을 주고 싶지 않았습니다.
그래서 Jackson DISTY 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());
}
나도 요즘 같은 문제에 부딪혔는데 좀 더 자세한 내용이 다른 사람에게 도움이 될지도 몰라.
REST API에 대한 보안 가이드라인을 찾다가 json 어레이에 관한 매우 흥미로운 문제를 발견했습니다.자세한 내용은 링크를 참조해 주세요.기본적으로 이 투고 질문에서 이미 살펴본 바와 같이 오브젝트 내에서 그것들을 랩해야 합니다.
즉, 다음과 같은 것이 아니라
[
{
"name": "order1"
},
{
"name": "order2"
}
]
항상 다음을 수행하는 것이 좋습니다.
{
"data": [
{
"name": "order1"
},
{
"name": "order2"
}
]
}
이것은 GET을 실행할 때 매우 간단하지만, 같은 json을 POST/PUT하려고 하면 문제가 발생할 수 있습니다.
제 경우 목록인 GET과 동일한 json을 받는 POST/PUT이 여러 개 있었습니다.
따라서 목록에는 매우 간단한 Wrapper 객체를 사용합니다.
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를 사용하여 작성되었습니다.
@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": [
{...}
]
}
de Wrapper Object를 사용하는 것만으로는 디폴트입니다.
@PostMapping("/resource")
public ResponseEntity<Void> setResources(@RequestBody Wrapper<ResourceDTO> wrappedResources) {
List<ResourceDTO> resources = wrappedResources.getData();
// your code here
return ResponseEntity
.ok()
.build();
}
바로 그거였어!도움이 됐으면 좋겠는데
주의: Spring Boot 1.5.5로 테스트 완료.해방.
@JsonFormat(with = JsonFormat.Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY)
private List< COrder > orders;
WAY와 오랫동안 씨름한 끝에, 여기 아주 쉬운 해결책이 있습니다.
컨트롤러가 찾고 있던 것은
@RequestBody List<String> ids
그리고 요청 주체는
{
"ids": [
"1234",
"5678"
]
}
해결책은 단순히 몸을 바꿔서
["1234", "5678"]
네, 그렇게 쉬워요
Spring 프레임워크를 사용하여 작성한 REST API에서 이 문제가 발생하였습니다.(응답이 JSON이 되도록) @ResponseBody 주석을 추가하면 해결되었습니다.
일반적으로 JSON 노드를 Java 객체의 노드에 매핑하는 데 문제가 있을 때 이 문제가 발생합니다.스웨거에서는 노드가 Type array로 정의되어 있고 JSON 오브젝트에 요소가1개밖에 없기 때문에 시스템이 하나의 요소 리스트를 어레이에 매핑하는 데 어려움을 겪고 있었기 때문에 같은 문제에 직면했습니다.
스웨거에서 요소는 다음과 같이 정의되었습니다.
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(No content POST)입니다.설명한 와 같이 그 에 유효한이 포함되어 있지 않기 수 없었기 입니다(OP의 제한사항).요구에 유효한 JSON이 포함되어 있지 않기 때문에 자동으로 애플리케이션/json 요구로 특정할 수 없었기 때문입니다(서버상의 제한).consumes = "application/json"
유효한 JSON 요구는 다음과 같습니다.엔티티에 null body 및 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);
제 경우 잭슨 라이브러리를 사용하여 JSON 파일을 읽었을 때 JSON 파일에 오브젝트가 1개밖에 포함되어 있지 않았기 때문에 오류가 발생하고 있었습니다.따라서 "{"로 시작하여 "}"로 끝납니다.그러나 읽어서 변수에 저장하는 동안 Array 오브젝트에 저장하고 있었습니다(내 경우처럼 여러 오브젝트가 있을 수 있습니다).
따라서 JSON 파일의 선두에 ""를, 마지막에 ""를 추가하여 오브젝트 배열로 변환하면 오류 없이 완벽하게 동작합니다.
같은 문제로 작업 중이었는데, 한 번에 여러 개의 레코드를 저장하고 싶었습니다.
많은 연구 끝에, 나는 즉시 효과가 있는 쉬운 해결책을 찾아냈다.
문제 코드를 해결하기 전에:
컨트롤러 방식
@PostMapping("/addList")
public ResponseEntity<List<Alarm>> saveAlarmList(@RequestBody List<AlarmDTO> dtos) {
return ResponseEntity.ok(alarmService.saveAlarmList(dtos));
}
서비스 방법
public List<Alarm> saveAlarmList(List<AlarmDTO> dtos) {
List<Alarm> alarmList = new ArrayList<>();
for (AlarmDTO dto: dtos) {
Alarm newAlarm = AlarmDtoMapper.map(dto);
alarmList.add(newAlarm);
}
return alarmRepository.saveAll(alarmList);
}
엔티티 클래스
public class Alarm{
@Id
@Basic(optional = false)
@NotNull
@Column(name = "alarm_id")
private Long alarmId;
@Basic(optional = false)
@NotNull
@Size(min = 1, max = 100)
@Column(name = "alarm_name")
private String alarmName;
}
우체부 오브젝트
[
{
"alarmId":"55",
"alarmName":"fgdffg",
},
{
"alarmId":"77788",
"alarmName":"hjjjjfk",
}
]
및 다른 형식
{
"list": [
{
"alarmId":"55",
"alarmName":"fgdffg",
},
{
"alarmId":"77788",
"alarmName":"hjjjjfk",
}
]
}
두 방법 모두 시리얼화/디시리얼화 오류가 발생하고 있습니다.
다음으로 엔티티 클래스에서 Serializable 인터페이스를 구현했습니다.
엔티티 클래스
public class Alarm implements Serializable
{
@Id
@Basic(optional = false)
@NotNull
@Column(name = "alarm_id")
private Long alarmId;
@Basic(optional = false)
@NotNull
@Size(min = 1, max = 100)
@Column(name = "alarm_name")
private String alarmName;
}
이 수정 후 우체부로부터의 첫 번째 유형의 요청 객체가 작동했습니다.
언급URL : https://stackoverflow.com/questions/20837856/can-not-deserialize-instance-of-java-util-arraylist-out-of-start-object-token
'programing' 카테고리의 다른 글
각 요소를 슬롯에 랩하려면 어떻게 해야 하나요? (0) | 2022.08.25 |
---|---|
이.$store.dispatch().then()은 Vuex에서 작동하지 않습니다. (0) | 2022.08.25 |
어레이 Vuex의 뮤트 (0) | 2022.08.18 |
다른 문자열 리터럴에 대한 두 문자 포인터의 주소가 동일합니다. (0) | 2022.08.18 |
이 .c 파일 #에는 왜 포함되어 있습니까? (0) | 2022.08.18 |