START_OBJECT টোকেনের বাইরে java.util.ArrayList এর উদাহরণটি deserialize করতে পারে না


129

আমি Listকয়েকটি কাস্টম অবজেক্ট পোস্ট করার চেষ্টা করছি । আমার জেএসএন অনুরোধের বডিটি হ'ল:

{
    "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

সমস্যাটি হ'ল জেএসএন - এটি ডিফল্টরূপে ডিসরিয়ালাইজ করা যায় Collectionনা কারণ এটি আসলে জাসন অ্যারে নয় - যা দেখতে এটির মতো হবে:

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

যেহেতু আপনি ডিসিরিয়ালাইজেশনের সঠিক প্রক্রিয়াটি নিয়ন্ত্রণ করছেন না (রেস্টইসিটি করে) - প্রথম বিকল্পটি হ'ল জেএসওএনকে কেবল ইনজেক্ট করা Stringএবং তারপরে deserialization প্রক্রিয়াটি নিয়ন্ত্রণ করা:

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

আপনি নিজেই এটি না করার সুবিধার্থে কিছুটা আলগা করবেন তবে আপনি সহজেই সমস্যাটি সমাধান করে ফেলবেন।

আরেকটি বিকল্প - যদি আপনি জেএসএন পরিবর্তন করতে না পারেন - তা হ'ল আপনার জেএসওএন ইনপুটটির কাঠামোর সাথে মানিয়ে নিতে একটি মোড়ক তৈরি করা - এবং পরিবর্তে এটি ব্যবহার করুন Collection<COrder>

আশাকরি এটা সাহায্য করবে.


1
দুর্দান্ত, আমি সংগ্রহটি মুড়ে ফেলেছি কারণ রেস্টেসি ডক্সে একটি উদাহরণ ছিল তবে এটি এক্সএমএল সহ ছিল।
ইসাহ

2
@ আইসাহ সুন্দর, আপনি কি এই পুনরায় যোগাযোগ লিঙ্কটি এখানে ভাগ করে নিতে পারেন দয়া করে
ন্যানোস্পেক

সিদ্ধান্তে আস. আমি বেশ নিশ্চিত যে আমার কাছে সঠিক কোড রয়েছে এবং কয়েক ঘন্টা এটি ডিবাগ করা এবং পথে আমার কোডগুলি পরিবর্তন করা pretty দেখা যাচ্ছে যে আমার পোস্টটি অ্যারে বলে চিহ্নিত করতে আমি কেবল স্কোয়ার ব্র্যাকেটগুলি অনুপস্থিত ছিল .আরর্গ আমি মনে করি এটি একটি নতুন অভিশাপ, এলওএল is JSON এবং স্প্রিং ডেটাতে নতুন কারও কাছে, আমার পদক্ষেপ অনুসরণ করবেন না। :(
iamjoshua

কোডটি আমার পক্ষে কাজ করছে না, নিয়ামক মধ্যে প্রত্যাশিত কোডটি কী হওয়া উচিত?
প্রিম30488

62

JSON ডকুমেন্টের পরিবর্তে আপনি নীচের মতো অবজেক্টম্যাপার অবজেক্টটি আপডেট করতে পারেন:

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

1
আপনাকে ধন্যবাদ, উত্তরটি আমাকে সাহায্য করেছে
জেসেস সানচেজ

ফ্যান্টাস্টিক! আপনি একটি দিন বাঁচিয়েছেন।
হার্ভ মুটোম্বো

ধন্যবাদ, দয়া করে আমাদের সাইটটি mboot.herokuapp.com দেখুন , আমরা সম্পর্কিত জাভা - বসন্ত-বুট
সালাহ আতওয়া

8

এটি কাজ করবে:

আপনি যখন জসননোড বা তদ্বিপরীত না হয়ে জসনআরে হিসাবে একক উপাদান সহ একটি তালিকা পড়ার চেষ্টা করছেন তখন সমস্যাটি হতে পারে ।

যেহেতু আপনি নিশ্চিতরূপে জানতে পারবেন না যে প্রত্যাবর্তিত তালিকায় একটি একক উপাদান রয়েছে (তাই জেসনটি দেখতে এই {...} ) বা একাধিক উপাদান রয়েছে (এবং জসন এটি দেখতে [{...}, {... }] ) - আপনাকে রানটাইমটিতে উপাদানটির ধরণটি পরীক্ষা করতে হবে।

এটিকে ঐটির মত দেখতে হবে:

(দ্রষ্টব্য: এই কোডের নমুনায় আমি 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 এর সদস্য ভেরিয়েবলের ভিতরে প্রকৃত ডেটা রাখার জন্য নির্দেশনা দেবে এবং আপনি যে API এর অনুরোধে সন্ধান করছেন সে JSON উত্পাদন করবে।

উদাহরণ:

public class ApiRequest {

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

   // getters
}

তারপরে প্যারামিটারের ধরণের পরিবর্তে COrderRestService.postOrder()আপনার নতুন ApiRequestমোড়ক POJO হতে হবে Collection<COrder>


2

আমি আজকাল এই একই সমস্যায় পড়েছি এবং সম্ভবত আরও কিছু বিশদ অন্য কারও পক্ষে সহায়ক হতে পারে।

আমি আরইএসটি এপিআইয়ের জন্য কিছু সুরক্ষা নির্দেশিকা সন্ধান করছিলাম এবং জসন অ্যারেগুলির সাথে একটি খুব আগ্রহজনক সমস্যাটি অতিক্রম করলাম । বিশদটির জন্য লিঙ্কটি চেক করুন, তবে মূলতঃ আপনি এটিকে কোনও অবজেক্টের মধ্যে মোড়ানো উচিত যেমন আমরা ইতিমধ্যে এই পোস্টের প্রশ্নটিতে দেখেছি।

সুতরাং, পরিবর্তে:

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

এটি সর্বদা পরামর্শ দেওয়া উচিত:

  {
    "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();
}

ঐটা এটা ছিল! আশা করি এটি কাউকে সাহায্য করবে।

দ্রষ্টব্য: স্প্রিংবুট 1.5.5.RELEASE দিয়ে পরীক্ষিত ।


1
মোড়কের ক্লাসটি আসল
ওমিড রোস্তামি

0

আমার কাছে এই সমস্যাটি একটি REST এপিআইতে ছিল যা স্প্রিং ফ্রেমওয়ার্ক ব্যবহার করে তৈরি করা হয়েছিল। একটি @ রেসপন্সবডি টীকা যুক্ত করা (প্রতিক্রিয়া জেএসএন করার জন্য) এটি সমাধান করেছে।


0

সাধারণত জাভা অবজেক্টের সাথে জেএসএন নোড ম্যাপিংয়ে সমস্যা হয় তখন আমরা এই সমস্যার মুখোমুখি হই। আমি একই সমস্যার মুখোমুখি হয়েছিল কারণ সোয়াগারে নোডটি টাইপ অ্যারে হিসাবে সংজ্ঞায়িত করা হয়েছিল এবং জেএসওএন অবজেক্টটিতে একটি মাত্র উপাদান ছিল, সুতরাং সিস্টেমটিকে একটি অ্যারের তালিকায় ম্যাপিংয়ে অসুবিধা হচ্ছিল।

Swagger এ উপাদান হিসাবে সংজ্ঞায়িত করা হয়েছিল

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

আমার পরীক্ষায় আমি উদ্দেশ্যমূলকভাবে অনুরোধটি নাল হিসাবে সেট করেছি (কোনও সামগ্রী পোস্ট নেই)। পূর্বে উল্লিখিত হিসাবে, ওপিটির কারণ একই ছিল কারণ অনুরোধটিতে বৈধ জেএসওএন নেই, সুতরাং এটি স্বয়ংক্রিয়ভাবে অ্যাপ্লিকেশন / জেএসএন অনুরোধ হিসাবে চিহ্নিত করা যায়নি যা সার্ভারের সীমাবদ্ধতা ছিল ( consumes = "application/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

আমার ক্ষেত্রে, ত্রুটিটি প্রদর্শিত হচ্ছে কারণ যখন আমি জ্যাকসন লাইব্রেরিটি ব্যবহার করে আমার জেএসএন ফাইলটি পড়ছিলাম, তখন আমার জেএসওএন ফাইলটিতে কেবলমাত্র 1 টি অবজেক্ট ছিল। সুতরাং এটি "{" দিয়ে শুরু হয়েছিল এবং "}" দিয়ে শেষ হয়েছিল। তবে এটি পড়তে এবং এটি একটি ভেরিয়েবলে সঞ্চয় করার সময়, আমি এটি একটি অ্যারে অবজেক্টে সংরক্ষণ করছিলাম (আমার ক্ষেত্রে যেমন 1 টিরও বেশি অবজেক্ট থাকতে পারে)।

সুতরাং, আমি আমার জেএসওএন ফাইলটির শেষে তাকে "[" শুরুতে এবং "]" যুক্ত করে এটিকে বস্তুর অ্যারে রূপান্তরিত করেছি এবং এটি কোনও ত্রুটি ছাড়াই পুরোপুরি সূক্ষ্মভাবে কাজ করেছে।


0

উপরে উল্লিখিত সমস্যার সমাধান হবে: mapper.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true);

তবে আমার ক্ষেত্রে প্রদানকারীর এটি [0..1] বা [0 .. *] সিরিয়ালাইজেশনটি বাগের পরিবর্তে করেছিল এবং আমি ফিক্সিং কার্যকর করতে পারি না। অন্যদিকে এটি অন্য সমস্ত ক্ষেত্রে আমার কঠোর ম্যাপারকে প্রভাবিত করতে চায় না যা কঠোরভাবে বৈধ হওয়া দরকার।

সুতরাং আমি একটি জ্যাকসন ন্যাসি হ্যাক করেছি (যা সাধারণভাবে অনুলিপি করা উচিত নয় ;-)), বিশেষত কারণ আমার সিঙ্গলঅরলিস্টিমেন্টে প্যাচ করার মতো কয়েকটি সম্পত্তি ছিল:

@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

@ জসনফরমেট (= জসনফর্ম্যাট সহ। ফিচার.এসিসিপিT_SINGLE_VALUE_AS_ARRAY) ব্যক্তিগত তালিকা <কর্ডার> আদেশ;


কোড ব্লকের ভিতরে কিছু কোড এবং আপনার উত্তরের যথার্থতার মূল্যায়ন করে কিছু পাঠ্য সহ একটি সম্পূর্ণ উত্তর সরবরাহ করুন
আইওনিস বড়াকোস
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.