I have a generic interface
public interface MyInterface<T> {
T method(T input);
}
and a couple of implementations of it, via ordinary classes like
public class MyClass<T> implements MyInterface<T> {
@Override
public T method(T input) {
T output = input; // whatever
return output;
}
}
and anonymous classes (see below). Now I want to test these implementations:
class TestClass1 {
// ...
}
class TestClass2 {
final int n;
final String s;
TestClass2(int n, String s) {
this.n = n;
this.s = s;
}
// ...
}
public class TestGenericImplementation {
private static <T> void makeTest(T testObject, MyInterface<T> impl) {
T output = impl.method(testObject);
if (output == null)
throw new NullPointerException();
// verify output further
}
// Question 1. How to specify the parameter here properly?
public static void testImplementation(MyInterface impl) {
// Question 2. How to avoid compiler warning about unchecked cast below?
// Doesn't work if impl is of type MyInterface<?> above
makeTest(new TestClass1(), impl);
makeTest(new TestClass2(1, "ABC"), impl);
// Ugly typecasts. Compiler complains.
makeTest(new TestClass1(), (MyInterface<TestClass1>) impl);
makeTest(new TestClass2(1, "ABC"), (MyInterface<TestClass2>) impl);
}
public static void main(String[] args) {
// Question 3. How to pass the interface argument here?
// Works but issues compiler warning about raw type
testImplementation(new MyClass());
testImplementation(new MyInterface() {
@Override
public Object method(Object input) {
return null; // whatever
}
});
// Looks ugly
testImplementation(new MyClass<Object>());
testImplementation(new MyInterface<Object>() {
@Override
public Object method(Object input) {
return null;
}
});
/* Diamond operator appeared only in Java 7,
* while generics were introduced in Java 5.
* What was the recommended way to solve this problem between 2004 and 2011?
* Besides that, this doesn't work for anonymous classes.
*/
testImplementation(new MyClass<>());
testImplementation(new MyInterface<>() { // Doesn't work
@Override
public Object method(Object input) {
return null;
}
});
testImplementation(x -> x); // Lambda exprssions are for simple cases only
}
}
The problem is that compiler is issuing a series of errors and warnings due to transition from a generic interface to its reified versions (those I need to use with the concrete classes TestClass1 and TestClass2 in place of the generic type variable T). Is it possible to avoid these warnings completely? If not (i.e. if they can only be suppressed), are there any pitfalls arising from this?
expects T to be the same for both arguments.
This presents a contradiction. In the first case T will be
TestClass1, in the second it will beTestClass2. If you were to use the generic version ofTest.MyInterface, there is no type that can possibly satisfy it. You're only getting away with this because you're using raw types. It can't beTest.MyInterface<TestClass1>andTest.MyInterface<TestClass2>simultaneously.You need to get rid of the
testImplementationmethod and stop using raw types. The first part of your main method might look like: