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?Accountes un modelo de Dropwizard que usacom.fasterxml.jackson.databind.annotationsRespuestas:
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 unaArrayListdeAccounts. Entonces vuelve al valor predeterminado.En su lugar, probablemente podría usar
as(JsonNode.class)y luego lidiar con elObjectMapperde 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
convertValuepodí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
CollectionTypelugar 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
Tque 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 tomaTypeTokens, 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
convertJsonen 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