ArrayList contains objects of the wrong type without explicit casting

Can anyone suggest how the given code could lead to such a problem, giving a random ClassCastException

one when the data is parsed from a file.

Details:

I have generic methods in a superclass.

public T getItem(int position) {
     return mItems.get(position); // mItems is an ArrayList
}
// corresponding setter
public void setItems(List<T> items) {
    mItems = items;
    notifyDataSetChanged();
}

      

It is then used in a subclass with T = AdItem

as shown below:

AdItem adItem = getItem(position);

      

Everything works fine, but I was getting random production crash reports with an exception on the above line:

java.lang.ClassCastException: com.google.gson.internal.LinkedTreeMap cannot be cast to .mypackage.AdItem

which obviously indicates that the list contains LinkedTreeMap

instead ofAdItem

The list is parsed from json and the code is type safe i.e. has no caste type, unverified warnings, etc.

What scripts ArrayList<AdItem>

contain LinkedTreeMap

runtime objects?

Except for the explicit uncontrolled / raw casting to Object

and from ArrayList

, which is not the case.

Parsing json from file:

ArrayList<AdItem> tempList = gson.fromJson(jsonReader, typeToken.getType());

      

Where

typeToken = new TypeToken<ArrayList<AdItem>>() {};

      

therefore tempList

should only contain AdItem

.

Can anyone explain how the ClassCastException can happen with the code above? Any additional details will be provided upon request.

+3


source to share


1 answer


By default, it will deserialize a JSON object into a LinkedHashMap if it doesn't recognize the provided type correctly.

Use the following code to get the type and try again:

TypeFactory.defaultInstance().constructCollectionType(ArrayList.class,AdItem.class)

or

new ObjectMapper().getTypeFactory().constructCollectionType(ArrayList.class,AdItem.class) // In case you are using ObjectMapper

      



i.e.

ArrayList<AdItem> tempList = gson.fromJson(jsonReader, TypeFactory.defaultInstance().constructCollectionType(ArrayList.class,AdItem.class));

      

+1


source







All Articles