START_OBJECT टोकन से बाहर java.util.ArrayList का उदाहरण नहीं दे सकते


129

मैं 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)

जवाबों:


156

समस्या JSON है - यह डिफ़ॉल्ट रूप से नहीं हो सकता है, Collectionक्योंकि यह वास्तव में एक JSON सरणी नहीं है, क्योंकि यह इस तरह दिखेगा:

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

चूंकि आप डिसेरिएलाइज़ेशन की सटीक प्रक्रिया को नियंत्रित नहीं कर रहे हैं (RestEasy does) - एक पहला विकल्प यह होगा कि आप केवल JSON को इंजेक्ट करें Stringऔर फिर डीसेरलाइज़ेशन प्रक्रिया को नियंत्रित करें :

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

आप अपने आप को ऐसा न करने की सुविधा को थोड़ा ढीला कर देंगे, लेकिन आप आसानी से समस्या को सुलझा लेंगे।

एक अन्य विकल्प - यदि आप JSON को बदल नहीं सकते हैं - अपने JSON इनपुट की संरचना को फिट करने के लिए एक आवरण का निर्माण किया जाएगा - और इसके बजाय इसका उपयोग करें Collection<COrder>

उम्मीद है की यह मदद करेगा।


1
महान, मैंने संग्रह में लपेटा क्योंकि रेस्टसी डॉक्स में एक उदाहरण था, लेकिन यह एक्सएमएल के साथ था।
isah

2
@ अच्छा, क्या आप उस बेचैनी की कड़ी को यहाँ साझा कर सकते हैं
नैनोपेस

जरा इस पर सोचो। मुझे पूरा यकीन है कि मेरे पास सही कोड है और यह घंटों तक डिबगिंग करता है, और मेरे कोड को रास्ते में बदल रहा है। पता चलता है कि मैं अपने वर्ग को इंगित करने के लिए वर्ग कोष्ठक को याद कर रहा था। वैसे मुझे लगता है कि यह एक newbies शाप है, LOL। JSON और स्प्रिंग डेटा में नए लोगों के लिए, मेरे नक्शेकदम पर न चलें। :(
ijjoshua

कोड मेरे लिए काम नहीं कर रहा है, नियंत्रक में अपेक्षित कोड क्या होना चाहिए?
prem30488

63

JSON दस्तावेज़ के बजाय, आप नीचे दिए गए ObjectMapper ऑब्जेक्ट को अपडेट कर सकते हैं:

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

1
धन्यवाद, उत्तर ने मेरी मदद की
जेसुअ सॅन्चेज़

बहुत खुबस! आपने एक दिन बचाया।
हेव मुतंबो

धन्यवाद, कृपया हमारी साइट mboot.herokuapp.com देखें , हम लेख संबंधित जावा - वसंत-बूट
सलाह अटवा

8

यह काम करेगा:

समस्या तब हो सकती है जब आप किसी एकल तत्व के साथ एक सूची को पढ़ने की कोशिश कर रहे हों, जैसे कि JsonNrray के बजाय एक 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 {
    ...
}

7

यूजेन के जवाब से संबंधित, आप इस विशेष मामले को एक रैपर POJO ऑब्जेक्ट बनाकर हल कर सकते हैं जिसमें Collection<COrder>इसके सदस्य चर के रूप में शामिल है । यह CollectionPOJO के सदस्य चर के अंदर वास्तविक डेटा को रखने के लिए जैक्सन को ठीक से निर्देशित करेगा और एपीआई अनुरोध में आपके द्वारा खोजे जा रहे JSON का उत्पादन करेगा।

उदाहरण:

public class ApiRequest {

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

   // getters
}

फिर COrderRestService.postOrder()अपने नए ApiRequestरैपर POJO होने के लिए पैरामीटर प्रकार सेट करें Collection<COrder>


2

मैं इन दिनों इसी समस्या में था और हो सकता है कि कुछ और विवरण किसी और के लिए सहायक हों।

मैं REST API के लिए कुछ सुरक्षा दिशानिर्देश देख रहा था और json arrays के साथ बहुत पेचीदा मुद्दे को पार कर गया । विवरण के लिए लिंक की जांच करें, लेकिन मूल रूप से, आपको उन्हें एक वस्तु के भीतर लपेट देना चाहिए जैसा कि हमने पहले ही इस पोस्ट प्रश्न में देखा था।

इसलिए, इसके बजाय:

  [
    {
      "name": "order1"
    },
    {
      "name": "order2"
    }
  ]

यह सलाह दी जाती है कि हम हमेशा ऐसा करें:

  {
    "data": [
      {
        "name": "order1"
      },
      {
        "name": "order2"
      }
    ]
  }

जब आप GET कर रहे होते हैं, तो यह बहुत सीधा होता है , लेकिन हो सकता है कि आपको बहुत तकलीफ हो, इसके बजाय, आपका वही POST / PUT करने की कोशिश कर रहा है ।

मेरे मामले में, मेरे पास एक से अधिक थे GET था जो कि एक सूची थी और एक से अधिक POST / PUT थी जो बहुत ही समान जसन प्राप्त करेंगे।

इसलिए मैं जो कर रहा हूं वह बहुत ही सरल प्रयोग था एक सूची के लिए एक आवरण वस्तु :

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": [
      {...}
    ]
  }

डिसेरिअलाइज़ेशन अभी भी डिफ़ॉल्ट था, बस डी का उपयोग कर रहा था व्रपर ऑब्जेक्ट :

@PostMapping("/resource")
public ResponseEntity<Void> setResources(@RequestBody Wrapper<ResourceDTO> wrappedResources) {
  List<ResourceDTO> resources = wrappedResources.getData();
  // your code here
  return ResponseEntity
           .ok()
           .build();
}

वह यह था! आशा है कि यह किसी की मदद करता है।

नोट: स्प्रिंगबूट 1.5.5 के साथ परीक्षण किया गया । कृपया ध्यान दें


1
रैपर वर्ग वास्तविक है
ओमिड रोस्तमी

0

मेरे पास REST API पर यह समस्या थी जो स्प्रिंग फ्रेमवर्क का उपयोग करके बनाई गई थी। @ResponseBody एनोटेशन जोड़ना (प्रतिक्रिया JSON बनाने के लिए) ने इसे हल किया।


0

आम तौर पर हम इस मुद्दे का सामना करते हैं जब जावा ऑब्जेक्ट के साथ JSON नोड मैप करने में समस्या होती है। मैंने एक ही मुद्दे का सामना किया क्योंकि स्वैगर में नोड को टाइप एरे के रूप में परिभाषित किया गया था और JSON ऑब्जेक्ट में केवल एक तत्व था, इसलिए सिस्टम को एरे के लिए एक एलिमेंट लिस्ट को मैप करने में कठिनाई हो रही थी।

स्वैगर में तत्व को परिभाषित किया गया था

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

जबकि ऐसा होना चाहिए

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

और TestNewटाइप एरे का होना चाहिए


0
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);
        }

0

वही मुद्दा:

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);

अपने परीक्षण में मैंने जानबूझकर अनुरोध को शून्य (कोई सामग्री POST) के रूप में सेट नहीं किया है। जैसा कि पहले उल्लेख किया गया है, ओपी का कारण एक ही था क्योंकि अनुरोध में वैध 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);

0

मेरे मामले में, त्रुटि दिखाई जा रही थी क्योंकि जब मैं जैक्सन लाइब्रेरी का उपयोग करके अपनी JSON फाइल पढ़ रहा था, मेरी JSON फाइल में केवल 1 ऑब्जेक्ट था। इसलिए यह "{" से शुरू हुआ और "}" से समाप्त हुआ। लेकिन इसे पढ़ते हुए और इसे एक चर में संग्रहीत करते हुए, मैं इसे एक सरणी ऑब्जेक्ट में संग्रहीत कर रहा था (जैसा कि मेरे मामले में, 1 से अधिक ऑब्जेक्ट हो सकता है)।

इसलिए, मैंने अपनी JSON फ़ाइल के अंत में "प्रारंभ में" और "]" को ऑब्जेक्ट की एक सरणी में परिवर्तित करने के लिए जोड़ा और यह बिना किसी त्रुटि के पूरी तरह से ठीक काम किया।


0

जैसा कि ऊपर बताया गया है कि समस्या का समाधान होगा: mapper.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);

हालाँकि मेरे मामले में प्रदाता ने यह किया था [0..1] या [0 .. *] बग के रूप में क्रमबद्धता और मैं फिक्सिंग को लागू नहीं कर सका। दूसरी ओर यह अन्य सभी मामलों के लिए मेरे सख्त मैपर को प्रभावित नहीं करना चाहता था, जिन्हें कड़ाई से मान्य करने की आवश्यकता है।

इसलिए मैंने एक जैक्सन NASTY 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());
  }

-1

@JsonFormat (= JsonFormat.Feature.ACCEPT_SINGLE_VALUE_AS_ARRAY) निजी सूची <COrder> के आदेशों के साथ;


कृपया कोड ब्लॉक के अंदर कुछ कोड और अपने उत्तर की शुद्धता का मूल्यांकन करने वाले कुछ टेक्स्ट के साथ एक पूर्ण उत्तर प्रदान करें
Ioannis Barakos
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.