views:

106

answers:

4

Hello,

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

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.

Please help me remove this generic warning.

Thanks

Shekhar

A: 

seem to discuss the same warning...

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

santa
Noel M
+2  A: 

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.)

fd
Thanks for the edit, apparently I fail at escaping angle brackets or something...
fd
+6  A: 

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

polygenelubricants
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<String>`, and `Set<Integer> nums = newSet(SpecializedStringSet.class);` could throw `ClassCastException` at run-time on `add`, right? I'll edit this into the answer based on comments.
polygenelubricants
@polygenelubricants, you are correct, it is not safe, that is why you have to suppress warnings.
Yishai
@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
@polygenelubricants, you demonstrated that it is unsafe in your comment.
Yishai
A: 

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