Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to fix: java.lang.ClassCastException: java.util.ArrayList cannot be cast to double[]

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();
    }
}
like image 550
Michael Avatar asked Oct 15 '25 10:10

Michael


1 Answers

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

like image 71
Andy Brown Avatar answered Oct 16 '25 23:10

Andy Brown



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!