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)
returnsnull
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 methodJClass
is a representation of a java class, it's a custom structure
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 likemCache = JCS.getInstance("uniqueNameForWrapper");
for all your wrappers?