Take the 2-minute tour ×
Stack Overflow is a question and answer site for professional and enthusiast programmers. It's 100% free, no registration required.

I encountered a problem when I tried to run the following code:

When I trying to get item from ArrayList<double[]> list but it throws ClassCastException

Method list.get(i) also throws excexption

public void drawRoutes(ArrayList<String> routes) {
    if (routes.isEmpty()) return;
    for (int i = 0; i < routes.size(); i++) {
        PolylineOptions polylineOptions = new PolylineOptions();
        ArrayList<double[]> list = TransportRoutes.getRoutes(tag, routes).get(i);
        for (double[] points : list) {  // throws ClassCastException
            map.addPolyline(polylineOptions
                    .add(new LatLng(points[0], points[1]))
                    .color(color)
                    .width(POLY_LINE_WIDTH));
        }
    }
}

method getRoutes() :

public static ArrayList<ArrayList<double[]>> getRoutes(String tag, ArrayList<String> numbers) {
    ArrayList<ArrayList<double[]>> routes = new ArrayList<>();
    for (String number : numbers) {
        routes.add(sRoutesHashMap.get(tag).get(number));
    }
    return routes;
}


// sRoutesHashMap is a HashMap<String, HashMap<String, ArrayList<double[]>>>
// and taken from this method


    protected static <T> T getSmth(Context context, String url) {
    T data = null;
    JSONParser jsonParser = new JSONParser(context);
    String json;
    ObjectMapper mapper = new ObjectMapper();
    try {
        json = jsonParser.execute(url).get();
        if (json != null) {
            data = mapper.readValue(json, new TypeReference<T>() {});
        } else return null;
    } catch (InterruptedException | ExecutionException | IOException e) {
        e.printStackTrace();
    }
    return data;
}

Full stacktrace is:

java.lang.ClassCastException: java.util.ArrayList cannot be cast to double[]
            at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2211)
            at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2261)
            at android.app.ActivityThread.access$600(ActivityThread.java:141)
            at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1256)
            at android.os.Handler.dispatchMessage(Handler.java:99)
            at android.os.Looper.loop(Looper.java:137)
            at android.app.ActivityThread.main(ActivityThread.java:5103)
            at java.lang.reflect.Method.invokeNative(Native Method)
            at java.lang.reflect.Method.invoke(Method.java:525)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:737)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
            at dalvik.system.NativeStart.main(Native Method)
     Caused by: java.lang.ClassCastException: java.util.ArrayList cannot be cast to double[]
            at in.transee.transee.Drawer.drawRoutes(Drawer.java:46)
            at in.transee.transee.MapsActivity.onCreate(MapsActivity.java:45)
            at android.app.Activity.performCreate(Activity.java:5133)
            at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1087)
            at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2175)
            at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2261)
            at android.app.ActivityThread.access$600(ActivityThread.java:141)
            at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1256)
            at android.os.Handler.dispatchMessage(Handler.java:99)
            at android.os.Looper.loop(Looper.java:137)
            at android.app.ActivityThread.main(ActivityThread.java:5103)
            at java.lang.reflect.Method.invokeNative(Native Method)
            at java.lang.reflect.Method.invoke(Method.java:525)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:737)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:553)
            at dalvik.system.NativeStart.main(Native Method)

When I used this method everythink worked:

public static void getAllRoutes(Context context) {
    String routesJson = sSPData.getString(sCity + ROUTES, EMPTY);
    ObjectMapper mapper = new ObjectMapper();
        JSONParser jsonParser = new JSONParser();
        try {
            routesJson = jsonParser.execute(URL + sCity + SEPARATOR + ROUTES).get().get(0);
        } catch (InterruptedException | ExecutionException e) {
            e.printStackTrace();
        }
    }
    try {
        sRoutesHashMap = mapper.readValue(routesJson,
                new TypeReference<HashMap<String, HashMap<String, ArrayList<double[]>>>>() {});
    } catch (IOException e) {
        e.printStackTrace();
    }
}
share|improve this question
    
Which package is ObjectMapper from? –  Andy Brown Feb 20 at 20:07
    
com.fasterxml.jackson.databind.ObjectMapper –  Michael Feb 20 at 20:10
    
Can you elaborate on the relationship between sRoutesHashMap and the method getSmth? –  antonio Feb 20 at 20:11
    
I can set type in TypeReference inside method getSmth directly and it will work. But I want to use generics.. –  Michael Feb 20 at 20:21

1 Answer 1

up vote 0 down vote accepted

It looks like you are getting heap pollution . The good news is I think you can get round it really easily by doing.

protected static <T> T getSmth(TypeReference<T> typeRef, Context context, String url) {
  ...
  data = mapper.readValue(json, typeRef);

And calling it with:

sRoutesHashMap = getSmth(new TypeReference<HashMapOfBlahBlahBlah>(){}, context, url);

Why heap pollution?

  • mapper.readValue either returns Object, or it returns T but is marked with @SuppressWarnings("unchecked") (I couldn't work out which, probably the latter)
  • you store the return as your generic type (bingo, here's your heap pollution)
  • but in the generic method the Object returned from mapper.readValue isn't actually of your generic type
  • and this only manifests itself later with your ClassCastException

Note: anywhere you see @SuppressWarnings("unchecked") either on your generic code or on library generic code you should be careful as this outcome is likely

How heap pollution?

The cause is probably because the anonymous new TypeReference<T>(){} in your generic getSmth method can't evaluate the type T as your concrete type argument. If you look at the source code for TypeReference this seems to make sense due to the way it uses getGenericSuperclass and getActualTypeArguments.

A solution would be to create your parameterized type of TypeReference outside getSmth and pass it as an argument into the method.

Test for heap pollution?

If I run this test program, you can probably see what I mean, and doing this on your environment will confirm it all:

static TypeFactory typeFactory = TypeFactory.defaultInstance();
public static void main(String[] args) {
    TestRig.<List<String>>pharaoh();                  // oh, that's bad
    TestRig.sam(new TypeReference<List<String>>(){}); // no, that's good
}
public static <T> void pharaoh() {
    TypeReference<?> typeRef = new TypeReference<T>() {};
    JavaType typeT = typeFactory.constructType(typeRef); // this is what happens inside ObjectMapper
    System.out.println("from generic  TypeReference: " + typeRef.getType().toString());
    System.out.println("from generic  TypeReference: " + typeT.toString());
}
public static <T> void sam(TypeReference<T> typeRef) {
    JavaType typeT = typeFactory.constructType(typeRef); // this is what happens inside ObjectMapper
    System.out.println("from concrete TypeReference: " + typeRef.getType().toString());
    System.out.println("from concrete TypeReference: " + typeT.toString());
}

results:

from generic  TypeReference: T <--- booooo
from generic  TypeReference: [simple type, class java.lang.Object]
from concrete TypeReference: java.util.List <--- yaaaaaay
from concrete TypeReference: [collection type; class java.util.List, contains [simple type, class java.lang.String]]

Ref: Java Tutorials > Non-Reifiable Types

share|improve this answer
    
Here is the Gist for the sample code –  Andy Brown Feb 20 at 21:32
    
Thank you for the comprehensive answer! –  Michael Feb 21 at 13:10

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.