I am trying to add a type parameter to a class of an old API. I am faced with a problem, due to a feature of Java generics, that seems like it will cause a lot of client code to stop compiling.
I have a class like this, which I'd like to add a type parameter to:
class C {
List<String> getStrings() {
return Arrays.asList("dummy"); // Dummy implementation
}
Object getContent() {
// Dummy implementation. In reality an object of
// some specific type is returned.
return null;
}
}
Note that the return value of getStrings
is a list on which a member type has been specified.
After the addiction of a type parameter C
would look like this:
class C<T> {
List<String> getStrings() {
return Arrays.asList("dummy");
}
T getContent() {
return null;
}
}
And here comes the problem. Clients use the class C
like this:
class U {
static void m() {
// This compiles and works fine both before and after the
// type parameter is added.
C c = new C();
// ...
// This also compiles and works fine both before and after the
// type parameter is added.
Object cont = c.getContent();
// But this doesn't type check any more! Since c now has a raw type
// the return value of getStrings also has a raw type. So there
// will be a 'can't assign Object to String' error.
String s = c.getStrings().get(0);
}
}
For the clients the solution to the problem is easy: Just add an unbounded wildcard type to C
:
C<?> c = new C<>();
But there are many external clients of this API. It would be a big inconvenience if all code that uses C
would have to be updated, even in a trivial way, to make it compile.
Is there some way around this? Is there some way for me to add a type parameter to the class C
without breaking the build for all clients to the API?
The same mechanism of Java's generics has been discussed for example here, here and here, but they don't discuss solutions and workarounds.