mozboz
mozboz

Reputation: 1108

How to avoid having to use @SuppressWarnings("unchecked")?

I have a Cache object for persisting objects to disk, and the way I've implemented this causes me to have to use @SupressWarnings . I'm not a Java expert, but this seems like a code smell, and I'm wondering if there's a 'better' way to do what I'm doing here (for instance, somehow storing a Type when I write the cache, and reading this value to be able to instantiate a specific type?).

My Cache object looks like this (not-relevant code removed for brevity):

/**
 * Write object o to cache file
 * 
 * @param cacheName
 * @param o
 *            Serializable object to write to cache
 */
public static void put(String cacheName, Serializable o) throws IOException {
    FileOutputStream fos = new FileOutputStream(getHashedFileName(cacheName));
    ObjectOutputStream oos = new ObjectOutputStream(fos);
    oos.writeObject(o);
    fos.close();
}

/**
 * Get an object from the cache. Caller should use exists() before calling
 * here to make sure the cache item exists otherwise Exception will be
 * thrown
 * 
 * @param cacheName
 * @return Object from cache
 */
public static Object get(String cacheName) throws CacheNotFoundException,
        IOException, ClassNotFoundException {
    FileInputStream fis = new FileInputStream(getHashedFileName(cacheName));
    ObjectInputStream ois = new ObjectInputStream(fis);
    Object o = ois.readObject();
    return o;
}

Because get() can return any type of object, I now have to cast it back to the original type when I read from the cache. I'm wondering if I can avoid generating the warning in the first place:

class somethingDoingSomeWork {

    /**
     * Save all work done to the cache.
     * @throws IOException
     */
    public void saveToCache() throws IOException {
        Cache.put(getCacheKey(), (MyObject<String>) summary);
    }

    /**
     * Repopulate from cache
     */
    @SuppressWarnings("unchecked")
    public boolean loadFromCache() throws IOException, CacheNotFoundException,
            ClassNotFoundException {
        // Code removed, checking for existence of cache, etc.

        // Cast required here, and this row generates unchecked warning
        summary = (MyObject<String>) Cache.get(getCacheKey());
        return true;
    }
}

Edit: For people suggesting moving @SuppressWarnings closer to the code, annotations can only be used on lines that are declarations, so this won't help me

Also using generics helps, but it appears to move the problem into the Cache.get() method. The best solution appears to be this: http://www.velocityreviews.com/forums/t499693-how-do-you-prevent-unchecked-cast-warning-when-reading-from-objectinputstream.html

Upvotes: 2

Views: 8208

Answers (3)

manocha_ak
manocha_ak

Reputation: 902

and I'm wondering if there's a 'better' way to do what I'm doing here (for instance, somehow storing a Type when I write the cache, and reading this value to be able to instantiate a specific type?)

Use generics here. If you have

public <String, P extends Serializable> R get( String key);
public <String, P extends Serializable> void put( String key, R value);

I am not pointing to already existing Cache implementations. Like Guava, those support cache anyways, but I blieve you want to improve this code.

At the last resort, One big thing is to always keep @SupressWarnings as close as possible to the code causing it.

Upvotes: 1

subodh
subodh

Reputation: 6158

Wherever you have like this

// Cast required here, and this row generates unchecked warning
summary = (MyObject) Cache.get(getCacheKey());

It will generates unchecked warning, to avoid this better option to make CollectionHelper class and generates unchecked warning in your CollectionHelper class. And use the CollectionHelper class to return the objects from that class.

For example,

public class CollectionsHelper {
    /**
     * 
     * @param list
     *            of List type
     * @return list - List of MyObject type
     */
    @SuppressWarnings("unchecked")
    public static List<MyObject> getMyObjects(List list) {
        return (List<MyObject>) list;
    }
}

and use it in this way

List<MyObject> objList = CollectionsHelper.getMyObjects(Cache.get(getCacheKey());

You don't need to add @SupressWarnings in your service or implementation class.

Upvotes: 0

stacker
stacker

Reputation: 68962

Assuming that both key and value are Serializable you could use these signatures

public <R extends Serializable, P extends Serializable> R get( P key);
public <R extends Serializable, P extends Serializable> void put( P key, R value);

Upvotes: 2

Related Questions