ClassCastException: datastructures.instances.JClass cannot be cast to java.util.ArrayList

496 views Asked by At

I know there are quite a few CCE questions on SO. I have read the majority of them either in detail or briefly and I cannot find anything that applies to my situation. My exact error is:

Exception in thread "pool-1-thread-1" java.lang.ClassCastException: datastructures.instances.JClass cannot be cast to java.util.ArrayList at if ((results = mCallsDownstreamCache.get(origin)) == null) {

As you will see in the code, what I'm doing is asking for an ArrayList from a cache (HashMap) and then making a decision on that. The odd behavior here is that datastructures.instances.JClass is in no way referenced in the piece of code that generates the error.

To give you some context, I have a database "model" which fulfills requests from a "controller". Those results are stored in a cache local to the model and if they exist the model will return the cache thus not having to hit the db. My caching elements are effectively decorators for the Commons' JCS.

The offending line is wrapped in a block comment and inline comment

public class AnalyzeModel extends Model {

    public final String TAG = getClass().getSimpleName();
    public CacheDecorator<Integer, JClass> mClassCache = new CacheDecorator<Integer, JClass>();
    public CacheDecorator<Integer, JMethod> mMethodCache = new CacheDecorator<Integer, JMethod>();
    public CacheDecorator<Integer, ArrayList<Integer>> mCallsUpstreamCache =
            new CacheDecorator<Integer, ArrayList<Integer>>();
    public CacheDecorator<Integer, ArrayList<Integer>> mCallsDownstreamCache =
            new CacheDecorator<Integer, ArrayList<Integer>>();

    public void close() {
        super.close();
    }

    public Pair<Integer, ArrayList<Integer>> selectCallGraphDownstream(int origin) {
        ArrayList<Integer> results = new ArrayList<Integer>();

        /**
         * This is the offending line
         */
        if ((results = mCallsDownstreamCache.get(origin)) == null) {
        // End error line
            results = new ArrayList<Integer>();
            for (Record r : mQuery.select(
                    mQuery.mQuerier.select(Calls.CALLS.TID)
                            .from(Calls.CALLS)
                            .where(Calls.CALLS.SID.eq(origin)))) {
                results.add(r.getValue(Calls.CALLS.TID));
            }
            mCallsDownstreamCache.put(origin, results);
            Statistics.CACHE_MISS++;
        } else {
            Statistics.CACHE_HITS++;
        }
        return new Pair<Integer, ArrayList<Integer>>(origin, results);
    }

}

public class CacheDecorator<K, V> {

    public final String TAG = getClass().getSimpleName();

    private CacheAccess<K, V> mCache;

    public CacheDecorator() {
        try {
            mCache = JCS.getInstance("default");
        } catch (CacheException e) {
            BillBoard.e(TAG, "Error getting cache configuration: " + e.toString());
            e.printStackTrace();
        }
    }

    /**
     * Get an object from cache
     * @param obj object to retrieve from cache
     * @return generic object of retrieved value, null if not found
     */
    public V get(K obj) {
        return mCache.get(obj);
    }

    /**
     * Place an object in cache
     * @param key generic key for reference
     * @param obj generic object to be cached
     */
    public synchronized void put(K key, V obj) {
        try {
            if(obj != null) {
                mCache.putSafe(key, obj);
            }
        } catch( CacheException e) {
            //BillBoard.d(TAG, obj.toString());
            //BillBoard.e(TAG, "Error placing item in cache: " + e.toString());
            //e.printStackTrace();
        }
    }

    /**
     * Get the stats from our cache manager
     * @return String of our cache object
     */
    public String getStats() {
        shutDownCache();
        return mCache.getStats();
    }

    public static void shutDownCache() {
        CompositeCacheManager.getInstance().shutDown();
    }
}

Some additional details that may, or may not, be helpful:

  • The Pair<V, K> datastructure is just an immutable 2-pair tuple class
  • CacheDecorator.get(V obj) returns null if the object doesn't exist in cache
  • I've tried quite a bit in regards to casting and such
  • JClass does have references elsewhere in the code, but no reference in the offending method
  • JClass is a representation of a java class, it's a custom structure
1

There are 1 answers

7
Brimzi On BEST ANSWER

By altering your config to include region-specific configs as presented in the documentation, and passing a region to your wrapper, should resolve the problem.

Looks like you are using the same cache region for all your wrappers and hence referencing the same 'under laying cache' across your wrappers. Could you change mCache = JCS.getInstance("default"); to something like mCache = JCS.getInstance("uniqueNameForWrapper"); for all your wrappers?