Me aparece el siguiente error:
java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to com.testing.models.Account
con el siguiente código
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);
¿Hay alguna razón por la que no pueda hacerlo get(0)
?
java
jackson
rest-assured
Ingeniero apasionado
fuente
fuente
Account
? ¿Por qué intentas enviar contenido desde un mapa?given()
se importa este método estáticamente?Account
es un modelo de Dropwizard que usacom.fasterxml.jackson.databind.annotations
Respuestas:
El problema viene de Jackson. Cuando no tiene suficiente información sobre a qué clase deserializar, usa
LinkedHashMap
.Dado que no le informa a Jackson el tipo de elemento de su
ArrayList
, no sabe que desea deserializar en unaArrayList
deAccount
s. Entonces vuelve al valor predeterminado.En su lugar, probablemente podría usar
as(JsonNode.class)
y luego lidiar con elObjectMapper
de una manera más rica de lo que permite la tranquilidad. Algo como esto: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);
fuente
convertValue
podía hacerlo en un solo paso. Ir a una cadena también funciona.Intente lo siguiente:
o:
List<POJO> pojos = mapper.convertValue( listOfObjects, new TypeReference<List<POJO>>() { });
Consulte la conversión de LinkedHashMap para obtener más información.
fuente
La forma en que pude mitigar el problema de JSON Array a la colección de objetos LinkedHashMap fue usando en
CollectionType
lugar de unTypeReference
. Esto es lo que hice y trabajé :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; }
Usando el
TypeReference
, todavía estaba obteniendo un ArrayList de LinkedHashMaps, es decir , no funciona :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; }
fuente
T
que no se podía cosificar a través de TypeToken, que suele ser más fácil. Personalmente prefiero el ayudante de guayaba porque todavía typesafe y no es específica a cualquier tipo de contenedor:return new TypeToken<List<T>>(){}.where(new TypeParameter<T>(){}, tClass)
. Pero Jackson no tomaTypeToken
s, entonces tú necesitas.getType()
.Tuve una excepción similar (pero un problema diferente)
java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to org.bson.Document
, y afortunadamente se resuelve más fácilmente:En vez de
List<Document> docs = obj.get("documents"); Document doc = docs.get(0)
que da error en la segunda línea, se puede usar
List<Document> docs = obj.get("documents"); Document doc = new Document(docs.get(0));
fuente
Resolver problema con dos métodos de análisis común
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; }
fuente
Tengo este método para deserializar un XML y convertir el tipo:
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 ); }
y esta es la llamada:
List<POJO> pojos = (List<POJO>) MyUtilClass.deserialize(xml, ArrayList.class,new TypeReference< List< POJO >>(){ });
fuente
Cuando usa jackson para mapear desde una cadena a su clase concreta, especialmente si trabaja con tipo genérico. entonces este problema puede ocurrir debido a un cargador de clases diferente. Lo conocí una vez con el siguiente escenario:
El proyecto B depende de la biblioteca A
en la biblioteca A:
public class DocSearchResponse<T> { private T data; }
tiene servicio para consultar datos de una fuente externa y usa jackson para convertir a una clase concreta
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>>() {}); } }
en el Proyecto B:
public class Account{ private String name; //come with other attributes }
y uso ServiceA de la biblioteca para realizar consultas y también convertir datos
public class ServiceAImpl extends ServiceA<Account> { }
y hacer uso de eso
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 } }
sucede porque desde el cargador de clases de LibraryA, jackson no puede cargar la clase de cuenta, luego simplemente anula el método
convertJson
en el proyecto B para dejar que jackson haga su trabajopublic class ServiceAImpl extends ServiceA<Account> { @Override public DocSearchResponse<T> convertJson(String result){ return mapper.readValue(result, new TypeReference<DocSearchResponse<T>>() {}); } } }
fuente