Fred
Fred

Reputation: 175

How to suppress unchecked typecast warning with generics not at declaration?

I have my code below which throws an unchecked typecast warning with the List assignment from ois.readObject(). Adding @SupressWarnings("unchecked") makes Android Studio give me an error saying "Annotations are not allowed here".

Is my only option to restructure the entire class so List tweets is declared on that line?

package com.fredliu.hellotwitter;

import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.Toast;

import com.fredliu.hellotwitter.models.Tweet;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.List;

public class TweetListActivity extends BaseListActivityWithMenu {
    private List<Tweet> tweets;
    private static final String cacheFile = "tweetCache.ser";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_tweet_list);
        try {
            FileInputStream fis = openFileInput(cacheFile);
            ObjectInputStream ois = new ObjectInputStream(fis);
            @SuppressWarnings(value="unchecked")
            tweets = (List<Tweet>) ois.readObject();

            ois.close();
            fis.close();
            Log.d("FREDFRED", "Tweets cache read from!");
        } catch (Exception e) {
            Log.e("FREDFRED", "Something horrible has happened when reading from the Tweets cache");
        }

        if (tweets == null || tweets.isEmpty()) {
            Toast.makeText(getApplicationContext(), "No stored Tweets found!", Toast.LENGTH_LONG).show();
            tweets = new ArrayList<>();
            for (int i = 1; i <= 20; i++) {
                Tweet t = new Tweet();
                t.setTitle("Title " + i);
                t.setBody("Body " + i);
                tweets.add(t);
            }
        }


        try {
            FileOutputStream fos = openFileOutput(cacheFile, MODE_PRIVATE);
            ObjectOutputStream oos = new ObjectOutputStream(fos);
            oos.writeObject(tweets);
            Log.d("FREDFRED", "Tweets successfully written to cache!");
        } catch (FileNotFoundException e) {
            Log.e("FREDFRED", "Tweet cache file not found" + e);
        } catch (IOException e) {
            Log.e("FREDFRED", "Object not found when writing Tweet to cache");
        }


        ArrayAdapter a = new TweetAdapter(this, tweets);
        setListAdapter(a);


    }

    @Override
    protected void onListItemClick(ListView l, View v, int position, long id) {
        Intent i = new Intent(this, TweetDetailActivity.class);
        startActivity(i);
        Toast.makeText(getApplicationContext(), "Position " + position + ", ID " + id, Toast.LENGTH_LONG).show();
    }
}

Upvotes: 3

Views: 5999

Answers (3)

Top-Master
Top-Master

Reputation: 8745

You can add @SuppressWarnings("unchecked") annotation, to suppress warnings from entire function/method, like:

@SuppressWarnings("unchecked")
MyResultType myFunction(MyInputType myValue)
{
    return (MyResultType) myValue;
}

Or add an inline-comment on each line, like:

//noinspection unchecked
tweets = (List<Tweet>) ois.readObject();

Where the difference is that the inline-comment is for IDE, and my Android compiler at least, ignores it and warns anyway.

However, said "suppress warnings from entire function" may hide some other issue, hence I prefer to use a helper, like:

MyType myVariable;

// ...

myVariable = Unchecked.cast( myValue );

Or in OP's case:

tweets = Unchecked.cast( ois.readObject() );

Which needs below to be added to project:

package my.package_name;

import androidx.annotation.NonNull;

/**
 * Helper similar to `@SuppressWarnings("unchecked")`, or `//noinspection unchecked` comment.
 *
 * <br><br><h2>The difference is that:</h2><ul>
 *
 * <li>Said annotation wraps entire function, causing more than needed to be ignored
 * (since it does not support being placed before R-value, at time of writing).
 *
 * <li>The compiler may ignore said comment, and warn anyway.
 */
@SuppressWarnings({"unused", "RedundantTypeArguments", "RedundantSuppression"})
public class Unchecked {
    /**
     * Type-cast implementation for reasons mentioned on {@link Unchecked} class.
     *
     * <br><br>Usage:
     * <pre>{@code
     * //noinspection RedundantTypeArguments
     * T myResult = Unchecked.<T>cast(myInput);
     * }</pre>
     *
     * <br><br>WARNING: To be sure compiler picks the right type,
     * set the type-argument, and suppress `RedundantTypeArguments`.
     */
    @SuppressWarnings("unchecked")
    public static <NewType> NewType cast(@NonNull Object value) {
        return (NewType) value;
    }
}

Upvotes: 0

Kevin Coppock
Kevin Coppock

Reputation: 134664

If you want to suppress a warning for a single statement, you can just insert the following:

// noinspection <checktype>

So for your case, for "unchecked", just change it to:

// noinspection unchecked
tweets = (List<Tweet>) ois.readObject();

EDIT: Another alternative would be to create some standalone method that performs the cast, and then apply the annotation to that method. Something like:

@SuppressWarnings("unchecked")
public static List<Tweet> asTweetList(ObjectInputStream ois) {
    return (List<Tweet>) ois.readObject();
}

and then use that instead:

FileInputStream fis = openFileInput(cacheFile);
ObjectInputStream ois = new ObjectInputStream(fis);
List<Tweet> tweets = asTweetList(ois);

That keeps the suppression scope tight, as well as not being IDE-specific.

Upvotes: 22

sravtej
sravtej

Reputation: 63

Annotations can not be attached to expressions, statements, or blocks. So your options in this case are to annotate the private member tweets, or the method onCreate with @SupressWarnings("unchecked"). You can even annotate the entire class TweetListActivity if you would like to suppress all unchecked warnings for that class (not recommended).

Upvotes: 1

Related Questions