3

I am trying to mock a generic interface, and whenever I mock it, I gets this warning:

The expression of type GenericInterface needs unchecked conversion to conform to GenericInterface<String>

My interface is

interface GenericInterface<T>{
    public T get();
}

and my test is

@Test
public void testGenericMethod(){
    GenericInterface<String> mockedInterface = EasyMock.createMock(GenericInterface.class);
}

I get warning at the first line in test case.

How do I remove this generic warning?

Johan
  • 71,222
  • 23
  • 174
  • 298
Shekhar
  • 5,321
  • 9
  • 38
  • 45

4 Answers4

10

The correct steps to get rid of the warning is:

  • First and foremost, prove that the unchecked cast is safe, and document why
  • Only then perform the unchecked cast, and annotate @SuppressWarnings("unchecked") on the variable declaration (not on the whole method)

So something like this:

// this cast is correct because...
@SuppressWarnings("unchecked")
GenericInterface<String> mockedInterface =
    (GenericInterface<String>) EasyMock.createMock(GenericInterface.class);

Guidelines

The following is excerpt from Effective Java 2nd Edition: Item 24: Eliminate unchecked warnings:

  • Eliminate every unchecked warning that you can.
  • If you can't eliminate a warning, and you can prove that the code that provoked the warning is typesafe, then (and only then) suppress the warning with @SuppressWarning("unchecked") annotation.
  • Always use the SuppressWarning annotation on the smallest scope possible.
  • Every time you use an @SuppressWarning("unchecked") annotation, add a comment saying why it's safe to do so.

Related questions


Refactoring the cast

It is also possible in most cases to perform the unchecked cast inside a generified createMock. It looks something like this:

static <E> Set<E> newSet(Class<? extends Set> klazz) {
    try {
        // cast is safe because newly instantiated set is empty
        @SuppressWarnings("unchecked")
        Set<E> set = (Set<E>) klazz.newInstance();
        return set;
    } catch (InstantiationException e) {
        throw new IllegalArgumentException(e);
    } catch (IllegalAccessException e) {
        throw new IllegalArgumentException(e);          
    }
}

Then elsewhere you can simply do:

// compiles fine with no unchecked cast warnings!
Set<String> names = newSet(HashSet.class);
Set<Integer> nums = newSet(TreeSet.class);

See also

Community
  • 1
  • 1
polygenelubricants
  • 348,637
  • 121
  • 546
  • 611
  • Asking for feedback: is it true that the cast in `newSet` is considered "safe"? I don't think it actually is, because one can create `SpecializedStringSet implements Set`, and `Set nums = newSet(SpecializedStringSet.class);` could throw `ClassCastException` at run-time on `add`, right? I'll edit this into the answer based on comments. – polygenelubricants Jul 12 '10 at 11:17
  • you are correct, it is not safe, that is why you have to suppress warnings. – Yishai Jul 12 '10 at 19:35
  • @Yishai: it's unchecked, which is why you have to suppress the warning. I'm wondering if it's also unsafe. Just because it's unchecked doesn't mean it's unsafe. If it's unsafe, then suppressing the warning is foolish. If it's provably safe, then suppress away and you're fine. – polygenelubricants Jul 12 '10 at 19:37
  • you demonstrated that it is unsafe in your comment. – Yishai Jul 13 '10 at 02:19
2

The problem here is that EasyMock.createMock() is going to return an object of type GenericInterface and not GenericInterface<String>. You could use the @SupressWarnings annotation to ignore the warning, or you could try and explicit cast to GenericInterface<String> (I think this just gives a different warning though.)

Péter Török
  • 109,525
  • 28
  • 259
  • 326
Mike Tunnicliffe
  • 10,204
  • 3
  • 28
  • 46
0

seem to discuss the same warning...

i guess @SuppressWarnings might be the key to happiness in that case

santa
  • 933
  • 9
  • 29
  • ... along with a comment explaning the justification for using `@SuppressWarnings` - http://books.google.co.uk/books?id=ka2VUBqHiWkC&lpg=PA117&ots=yXJnRho1Q1&dq=effective%20java%20suppresswarnings&pg=PA118#v=onepage&q&f=false – Noel M Jul 12 '10 at 10:43
0

If you are really stuck up on avoiding the compiler warning, you can declare an interface in your test just for the purpose of avoiding it.

 interface MockGenericInterface extends GenericInterface<String> {}

Then you can do:

 GenericInterface<String> mockedInterface = EasyMock.createMock(MockGenericInterface.class);
Yishai
  • 84,976
  • 26
  • 176
  • 250