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?
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
- What is
SuppressWarnings (“unchecked”)
in Java? - How do I address unchecked cast warnings?
- Type safety: Unchecked cast
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
- Java Tutorials/Generics
- Angelika Langer's Java Generics FAQ
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.)
- http://www.velocityreviews.com/forums/t147848-generics-in-1-5-nonsense-warnings.html
- http://forums.sun.com/thread.jspa?threadID=635608
seem to discuss the same warning...
i guess @SuppressWarnings might be the key to happiness in that case
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);
精彩评论