java.lang.ClassCastException: java.util.LinkedHashMap com.testing.models.Account पर नहीं डाला जा सकता है


84

मैं नीचे त्रुटि कर रहा हूँ:

java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to com.testing.models.Account

नीचे दिए गए कोड के साथ

final int expectedId = 1;

Test newTest = create();

int expectedResponseCode = Response.SC_OK;

ArrayList<Account> account = given().when().expect().statusCode(expectedResponseCode)
    .get("accounts/" + newTest.id() + "/users")
    .as(ArrayList.class);
assertThat(account.get(0).getId()).isEqualTo(expectedId);

क्या कोई कारण है कि मैं ऐसा क्यों नहीं कर सकता get(0)?


में ढाला नहीं जा सकता है क्या ? शेष त्रुटि संदेश क्या है?
ओलिवर चार्ल्सवर्थ

1
@ ऑलिवरचर्ल्सवर्थ ने पूरे स्टैकट्रेस को भी जोड़ा
इंजीनियर

2
क्या है Account? आप इसे एक नक्शे से डालने की कोशिश क्यों कर रहे हैं?
डेव न्यूटन

हममें से जो पुस्तकालय से अपरिचित हो सकते हैं, क्या आप कह सकते हैं कि इस given()पद्धति को किस वर्ग से आयात किया जाता है?
मार्क पीटर्स

@DaveNewton Dropwizard Accountकी एक मॉडल है जो प्रयोग करती हैcom.fasterxml.jackson.databind.annotations
इंजीनियर

जवाबों:


108

मुद्दा जैक्सन से आ रहा है। जब इसके बारे में पर्याप्त जानकारी नहीं होती है कि किस वर्ग को इसका उपयोग करना है, तो यह उपयोग करता है LinkedHashMap

चूंकि आप जैक्सन को अपने प्रकार के तत्व के बारे में नहीं बता रहे हैं ArrayList, इसलिए यह नहीं पता है कि आप किसी एक ArrayListके बारे में बताना चाहते हैं Account। तो यह डिफ़ॉल्ट पर वापस गिर जाता है।

इसके बजाय, आप शायद उपयोग कर सकते हैं as(JsonNode.class), और फिर ObjectMapperआराम से आश्वासन दिया की तुलना में एक अमीर तरीके से व्यवहार करते हैं । कुछ इस तरह:

ObjectMapper mapper = new ObjectMapper();

JsonNode accounts = given().when().expect().statusCode(expectedResponseCode)
    .get("accounts/" + newClub.getOwner().getCustId() + "/clubs")
    .as(JsonNode.class);


//Jackson's use of generics here are completely unsafe, but that's another issue
List<Account> accountList = mapper.convertValue(
    accounts, 
    new TypeReference<List<Account>>(){}
);

assertThat(accountList.get(0).getId()).isEqualTo(expectedId);

आप प्रतिक्रिया को एस्ट्रिंग () भी सेट कर सकते हैं, अतिरिक्त रूपांतरण करने से बचाता है - readValue पहले स्ट्रिंग के रूप में एक स्ट्रिंग को स्वीकार करेगा।
BIGDeutsch

@BIGDeutsch: बस इस पर फिर से गौर करते हुए, मुझे वहाँ वापस टोकन में परिवर्तित करने की कोई आवश्यकता नहीं थी जब convertValueयह एक चरण में कर सकता था। एक स्ट्रिंग पर जाना भी काम करता है।
मार्क पीटर्स

44

निम्नलिखित का प्रयास करें:

POJO pojo = mapper.convertValue(singleObject, POJO.class);

या:

List<POJO> pojos = mapper.convertValue(
    listOfObjects,
    new TypeReference<List<POJO>>() { });

अधिक जानकारी के लिए LinkedHashMap का रूपांतरण देखें ।


3
"कन्वर्टवैल्यू" दिखाने के लिए +1। मेरे पास एक ऐसा मामला था जहां मुझे एक विशेष संपत्ति को एक सूची के रूप में json से पढ़ने की आवश्यकता थी और यह वही है जो मुझे चाहिए था।
गेमशूट्स

28

जिस तरह से मैं JSON एरे को कम कर सकता था LinkedHashMap ऑब्जेक्ट्स समस्या के संग्रह केCollectionType बजाय एक का उपयोग करके किया गया था TypeReference। यह वही है जो मैंने किया और काम किया :

public <T> List<T> jsonArrayToObjectList(String json, Class<T> tClass) throws IOException {
    ObjectMapper mapper = new ObjectMapper();
    CollectionType listType = mapper.getTypeFactory().constructCollectionType(ArrayList.class, tClass);
    List<T> ts = mapper.readValue(json, listType);
    LOGGER.debug("class name: {}", ts.get(0).getClass().getName());
    return ts;
}

का उपयोग करते हुए TypeReference, मुझे अभी भी लिंक्डहाशमैप्स का एक ArrayList मिल रहा था, अर्थात काम नहीं करता है :

public <T> List<T> jsonArrayToObjectList(String json, Class<T> tClass) throws IOException {
    ObjectMapper mapper = new ObjectMapper();
    List<T> ts = mapper.readValue(json, new TypeReference<List<T>>(){});
    LOGGER.debug("class name: {}", ts.get(0).getClass().getName());
    return ts;
}

1
मेरी समस्या को भी सहेज लिया। धन्यवाद!
व्लादिमीर गिलेविच

1
+1, आपके मामले में अंतर यह था कि यह विधि स्वयं सामान्य थी इसलिए Tटाइपकोकेन के माध्यम से इसका पुनरीक्षण नहीं किया जा सकता था , जो आमतौर पर आसान होता है। व्यक्तिगत रूप से मैं अमरूद के सहायक को पसंद करता हूं, क्योंकि यह अभी भी असुरक्षित है और किसी भी कंटेनर प्रकार के लिए विशिष्ट नहीं है return new TypeToken<List<T>>(){}.where(new TypeParameter<T>(){}, tClass):। लेकिन जैक्सन नहीं लेता है TypeTokenतो आप की जरूरत है .getType()
मार्क पीटर्स

मेरी समस्या को भी सहेज लिया। धन्यवाद!
शशांक

6

मेरे पास एक समान अपवाद था (लेकिन अलग समस्या) - java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to org.bson.Documentऔर सौभाग्य से यह आसान हल है:

के बजाय

List<Document> docs = obj.get("documents");
Document doc = docs.get(0)

जो दूसरी पंक्ति पर त्रुटि देता है, एक का उपयोग कर सकते हैं

List<Document> docs = obj.get("documents");
Document doc = new Document(docs.get(0));

1

समस्या को दो विधि पार्स आम के साथ हल करें

  1. एक प्रकार की वस्तु है
public <T> T jsonToObject(String json, Class<T> type) {
        T target = null;
        try {
            target = objectMapper.readValue(json, type);
        } catch (Jsenter code hereonProcessingException e) {
            e.printStackTrace();
        }
    
        return target;
    }
  1. प्रकार के साथ संग्रह लपेटो वस्तु है
public <T> T jsonToObject(String json, TypeReference<T> type) {
    T target = null;
    try {
        target = objectMapper.readValue(json, type);
    } catch (JsonProcessingException e) {
        e.printStackTrace();
    }
    return target;
}

0

मेरे पास XML को डिस्क्रिब्लाइज करने और टाइप परिवर्तित करने के लिए यह विधि है:

public <T> Object deserialize(String xml, Class objClass ,TypeReference<T> typeReference ) throws IOException {
    XmlMapper xmlMapper = new XmlMapper();
    Object obj = xmlMapper.readValue(xml,objClass);
    return  xmlMapper.convertValue(obj,typeReference );   
}

और यह कॉल है:

List<POJO> pojos = (List<POJO>) MyUtilClass.deserialize(xml, ArrayList.class,new TypeReference< List< POJO >>(){ });

0

जब आप जैकसन का उपयोग स्ट्रिंग से अपने ठोस वर्ग तक के नक्शे में करते हैं, खासकर यदि आप सामान्य प्रकार के साथ काम करते हैं। तब अलग-अलग श्रेणी लोडर के कारण यह समस्या हो सकती है। मैं इसे एक समय में नीचे के साथ मिले:

प्रोजेक्ट बी लाइब्रेरी ए पर निर्भर करता है

लाइब्रेरी ए में:

public class DocSearchResponse<T> {
 private T data;
}

इसमें बाहरी स्रोत से डेटा क्वेरी करने और ठोस वर्ग में बदलने के लिए जैक्सन का उपयोग करने की सेवा है

public class ServiceA<T>{
  @Autowired
  private ObjectMapper mapper;
  @Autowired
  private ClientDocSearch searchClient;

  public DocSearchResponse<T> query(Criteria criteria){
      String resultInString = searchClient.search(criteria);
      return convertJson(resultInString)
  }
}

public DocSearchResponse<T> convertJson(String result){
     return mapper.readValue(result, new TypeReference<DocSearchResponse<T>>() {});
  }
}

प्रोजेक्ट B में:

public class Account{
 private String name;
 //come with other attributes
}

और मैं क्वेरी बनाने के लिए और साथ ही डेटा परिवर्तित करने के लिए लाइब्रेरी से सेवा का उपयोग करता हूं

public class ServiceAImpl extends ServiceA<Account> {
    
}

और उस का उपयोग करें

public class MakingAccountService {
    @Autowired
    private ServiceA service;
    public void execute(Criteria criteria){
      
        DocSearchResponse<Account> result = service.query(criteria);
        Account acc = result.getData(); //  java.util.LinkedHashMap cannot be cast to com.testing.models.Account
    }
}

ऐसा इसलिए होता है क्योंकि लाइब्रेरीए के क्लास लोडर से, जैकसन अकाउंट क्लास को लोड नहीं कर सकते हैं, तो जैकसन convertJsonको नौकरी देने के लिए प्रोजेक्ट बी में सिर्फ विधि को ओवरराइड करें

public class ServiceAImpl extends ServiceA<Account> {
        @Override
        public DocSearchResponse<T> convertJson(String result){
         return mapper.readValue(result, new TypeReference<DocSearchResponse<T>>() {});
      }
    }
 }
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.