Otrzymuję poniższy błąd:
java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to com.testing.models.Account
z poniższym kodem
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);
Czy istnieje powód, dla którego nie mogę tego zrobić get(0)
?
java
jackson
rest-assured
Inżynier z pasją
źródło
źródło
Account
? Dlaczego próbujesz przesyłać do niego z mapy?given()
metoda jest statycznie importowana?Account
to model z Dropwizard, który używacom.fasterxml.jackson.databind.annotations
Odpowiedzi:
Problem pochodzi od Jacksona. Gdy nie ma wystarczających informacji na temat klasy do deserializacji, używa
LinkedHashMap
.Ponieważ nie informujesz Jacksona o typie swojego elementu
ArrayList
, nie wie, że chcesz deserializować się na anArrayList
zAccount
s. Więc wraca do ustawień domyślnych.Zamiast tego prawdopodobnie mógłbyś użyć
as(JsonNode.class)
, a następnie poradzić sobie z nimiObjectMapper
w bogatszy sposób, niż pozwala na to pewność. Coś takiego: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);
źródło
convertValue
mógłbym to zrobić w jednym kroku. Przechodzenie do struny też działa.Spróbuj wykonać następujące czynności:
lub:
List<POJO> pojos = mapper.convertValue( listOfObjects, new TypeReference<List<POJO>>() { });
Aby uzyskać więcej informacji, zobacz konwersję LinkedHashMap .
źródło
Sposób, w jaki mogłem złagodzić problem z tablicą JSON w celu zbierania obiektów LinkedHashMap, polegał na użyciu
CollectionType
zamiast plikuTypeReference
. Oto, co zrobiłem i pracowałem :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; }
Używając
TypeReference
, nadal otrzymywałem ArrayList of LinkedHashMaps, tj. Nie działa :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; }
źródło
T
nie można jej było zreifikować za pomocą TypeToken, co jest zwykle łatwiejsze. Osobiście wolę pomocnika guawy, bo to wciąż typesafe i nie specyficzne dla każdego rodzaju pojemnika:return new TypeToken<List<T>>(){}.where(new TypeParameter<T>(){}, tClass)
. Ale Jackson nie bierzeTypeToken
tego, więc potrzebujesz.getType()
.Miałem podobny wyjątek (ale inny problem) -
java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to org.bson.Document
i na szczęście łatwiej go rozwiązać:Zamiast
List<Document> docs = obj.get("documents"); Document doc = docs.get(0)
co daje błąd w drugiej linii, można użyć
List<Document> docs = obj.get("documents"); Document doc = new Document(docs.get(0));
źródło
Rozwiąż problem za pomocą dwóch wspólnych metod analizy
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; }
źródło
Mam tę metodę deserializacji XML i konwertowania typu:
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 ); }
a to jest wezwanie:
List<POJO> pojos = (List<POJO>) MyUtilClass.deserialize(xml, ArrayList.class,new TypeReference< List< POJO >>(){ });
źródło
Kiedy używasz jacksona do mapowania z ciągu znaków na konkretną klasę, zwłaszcza jeśli pracujesz z typem ogólnym. wtedy ten problem może wystąpić z powodu innego programu ładującego klasy. spotkałem to kiedyś z poniższym scenariuszem:
Projekt B zależy od Biblioteki A
w bibliotece A:
public class DocSearchResponse<T> { private T data; }
ma usługę do przeszukiwania danych z zewnętrznego źródła i używa jsona do konwersji na konkretną klasę
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>>() {}); } }
w Projekcie B:
public class Account{ private String name; //come with other attributes }
i używam ServiceA z biblioteki do tworzenia zapytań i konwersji danych
public class ServiceAImpl extends ServiceA<Account> { }
i wykorzystaj to
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 } }
dzieje się tak, ponieważ z modułu ładującego klasy biblioteki A, jackson nie może załadować klasy konta, a następnie po prostu nadpisuje metodę
convertJson
w projekcie B, aby pozwolić jacksonowi wykonać swoją pracępublic class ServiceAImpl extends ServiceA<Account> { @Override public DocSearchResponse<T> convertJson(String result){ return mapper.readValue(result, new TypeReference<DocSearchResponse<T>>() {}); } } }
źródło