Ich erhalte den folgenden Fehler:
java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to com.testing.models.Account
mit dem folgenden Code
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);
Gibt es einen Grund, warum ich das nicht kann get(0)
?
java
jackson
rest-assured
Leidenschaftlicher Ingenieur
quelle
quelle
Account
? Warum versuchst du es von einer Karte aus zu besetzen?given()
Methode statisch importiert wird?Account
ist ein Modell von Dropwizard, das verwendetcom.fasterxml.jackson.databind.annotations
Antworten:
Das Problem kommt von Jackson. Wenn es nicht genügend Informationen darüber gibt, in welche Klasse es deserialisiert werden soll, wird es verwendet
LinkedHashMap
.Da Sie Jackson nicht über den Elementtyp Ihres Elements informieren
ArrayList
, weiß er nicht, dass Sie in einArrayList
vonAccount
s deserialisieren möchten . Es fällt also auf die Standardeinstellung zurück.Stattdessen könnten Sie wahrscheinlich das verwenden
as(JsonNode.class)
und dannObjectMapper
auf eine reichhaltigere Art und Weise damit umgehen , als es die Sicherheit zulässt. Etwas wie das: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);
quelle
convertValue
dies in einem Schritt möglich war. Zu einem String zu gehen funktioniert auch.Versuche Folgendes:
oder:
List<POJO> pojos = mapper.convertValue( listOfObjects, new TypeReference<List<POJO>>() { });
Weitere Informationen finden Sie unter Konvertierung von LinkedHashMap .
quelle
Die Art und Weise, wie ich das Problem mit dem JSON-Array für die Sammlung von LinkedHashMap-Objekten verringern konnte , war die Verwendung von
CollectionType
anstelle von aTypeReference
. Das habe ich getan und gearbeitet :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; }
Mit dem habe
TypeReference
ich immer noch eine ArrayList von LinkedHashMaps erhalten, dh funktioniert nicht :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; }
quelle
T
nicht über das TypeToken bestätigt werden konnte, was normalerweise einfacher ist. Persönlich bevorzuge ich Guavas Helfer, weil er immer noch typsicher und für keinen Containertyp spezifisch ist :return new TypeToken<List<T>>(){}.where(new TypeParameter<T>(){}, tClass)
. Aber Jackson nimmtTypeToken
s nicht, also brauchst du es.getType()
.Ich hatte eine ähnliche Ausnahme (aber ein anderes Problem) -
java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to org.bson.Document
und zum Glück ist es einfacher zu lösen:Anstatt
List<Document> docs = obj.get("documents"); Document doc = docs.get(0)
was Fehler in der zweiten Zeile gibt, kann man verwenden
List<Document> docs = obj.get("documents"); Document doc = new Document(docs.get(0));
quelle
Lösen Sie das Problem mit zwei Methoden
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; }
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; }
quelle
Ich habe diese Methode zum Deserialisieren eines XML und Konvertieren des Typs:
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 ); }
und das ist der Aufruf:
List<POJO> pojos = (List<POJO>) MyUtilClass.deserialize(xml, ArrayList.class,new TypeReference< List< POJO >>(){ });
quelle
Wenn Sie Jackson verwenden, um eine Zeichenfolge Ihrer konkreten Klasse zuzuordnen, insbesondere wenn Sie mit einem generischen Typ arbeiten. Dann kann dieses Problem aufgrund eines anderen Klassenladeprogramms auftreten. ich habe es einmal mit unten szenarior getroffen:
Projekt B hängt von Bibliothek A ab
in Bibliothek A:
public class DocSearchResponse<T> { private T data; }
Es verfügt über einen Dienst zum Abfragen von Daten aus externen Quellen und zum Konvertieren in eine konkrete Klasse mit Jackson
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>>() {}); } }
in Projekt B:
public class Account{ private String name; //come with other attributes }
und ich benutze ServiceA aus der Bibliothek, um Abfragen zu machen und auch Daten zu konvertieren
public class ServiceAImpl extends ServiceA<Account> { }
und nutzen Sie das
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 } }
Es kommt vor, dass Jackson vom Klassenladeprogramm von LibraryA die Account-Klasse nicht laden kann und dann einfach die Methode
convertJson
in Projekt B überschreibt , damit Jackson seine Arbeit erledigen kannpublic class ServiceAImpl extends ServiceA<Account> { @Override public DocSearchResponse<T> convertJson(String result){ return mapper.readValue(result, new TypeReference<DocSearchResponse<T>>() {}); } } }
quelle