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

JavaJacksonRest Assured

Java Problem Overview


I'm getting below error:

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

with below 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);

Is there a reason why I cannot do get(0)?

Java Solutions


Solution 1 - Java

The issue's coming from Jackson. When it doesn't have enough information on what class to deserialize to, it uses LinkedHashMap.

Since you're not informing Jackson of the element type of your ArrayList, it doesn't know that you want to deserialize into an ArrayList of Accounts. So it falls back to the default.

Instead, you could probably use as(JsonNode.class), and then deal with the ObjectMapper in a richer manner than rest-assured allows. Something like this:

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);

Solution 2 - Java

Try the following:

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

or:

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

See conversion of LinkedHashMap for more information.

Solution 3 - Java

The way I could mitigate the JSON Array to collection of LinkedHashMap objects problem was by using CollectionType rather than a TypeReference . This is what I did and worked:

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;
}

Using the TypeReference, I was still getting an ArrayList of LinkedHashMaps, i.e. does not work:

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;
}

Solution 4 - Java

I had a similar exception (but different problem) - java.lang.ClassCastException: java.util.LinkedHashMap cannot be cast to org.bson.Document , and fortunately it's solved easier:

Instead of

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

which gives error on second line, One can use

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

Solution 5 - Java

Solve problem with two method parse common

  1. Whith type is an object
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;
    }

2. With type is collection wrap object

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;
}

Solution 6 - Java

This is something i used in my project, Json object was returned, i converted it to a List of POJO, List and then accessed the element. I took the input of Json object from another microservice.

Main thing is:- JsonNode stocks = restTemplate.getForObject("http://localhost:2000/stocks/qty";, JsonNode.class); List stockList = mapper.convertValue(stocks, new TypeReference>() {});

@GetMapping("/")
    public List<Stock_id_qty> checkQty() throws JsonProcessingException {
        ObjectMapper mapper = new ObjectMapper();
        JsonNode stocks = restTemplate.getForObject("http://localhost:2000/stocks/qty", JsonNode.class);
        List<Stock_id_qty> stockList = mapper.convertValue(stocks, new TypeReference<List<Stock_id_qty>>() {});
        List<Stock_id_qty> result = new ArrayList<>();
        for(Stock_id_qty s : stockList){
            if(s.getStockQty() < 10)
            {
                result.add(s);
            }
        }
        return result;
    }

Solution 7 - Java

I have this method for deserializing an XML and converting the type:

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 );   
}

and this is the call:

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

Solution 8 - Java

When you use jackson to map from string to your concrete class, especially if you work with generic type. then this issue may happen because of different class loader. i met it one time with below scenarior:

Project B depend on Library A

in Library A:

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

it has service to query data from external source, and use jackson to convert to concrete class

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 Project B:

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

and i use ServiceA from library to make query and as well convert data

public class ServiceAImpl extends ServiceA<Account> {
    
}

and make use of that

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
    }
}

it happen because from classloader of LibraryA, jackson can not load Account class, then just override method convertJson in Project B to let jackson do its job

public class ServiceAImpl extends ServiceA<Account> {
        @Override
        public DocSearchResponse<T> convertJson(String result){
         return mapper.readValue(result, new TypeReference<DocSearchResponse<T>>() {});
      }
    }
 }

Solution 9 - Java

> public class ObjectHelper { > > private static ObjectMapper objectMapper = new ObjectMapper(); > > public static ObjectMapper getObjectMapper() { > objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL).configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES,false); > return objectMapper; > } > }

Use > FetchResponse fetchResponse = > ObjectHelper.getObjectMapper().convertValue( > data, new TypeReference() {});

OR

List<Map<String, Object>> responseObj = (List<Map<String, Object>>) response.get("content");

List<LkAuthUserDetail> responseData = ObjectHelper.getObjectMapper().convertValue(responseObj,
                    new TypeReference<List<LkAuthUserDetail>>() {});

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionPassionate EngineerView Question on Stackoverflow
Solution 1 - JavaMark PetersView Answer on Stackoverflow
Solution 2 - Javauser2578871View Answer on Stackoverflow
Solution 3 - JavaHimadri PantView Answer on Stackoverflow
Solution 4 - JavanurbView Answer on Stackoverflow
Solution 5 - JavaLove JavaView Answer on Stackoverflow
Solution 6 - Javasiddharth jainView Answer on Stackoverflow
Solution 7 - JavaMohamed FarghalyView Answer on Stackoverflow
Solution 8 - Javauncle bobView Answer on Stackoverflow
Solution 9 - JavaCodingBeeView Answer on Stackoverflow