1

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.

Daniel Widdis
  • 8,424
  • 13
  • 41
  • 63
Lii
  • 11,553
  • 8
  • 64
  • 88
  • 1
    Notice that your library update only affect new compiles in the client libraries, existing .class files are unaffected – Ferrybig Feb 02 '18 at 08:46

1 Answers1

1

Workaround proposal: you could create a new class CV2 (that could extend or not extent the existing class C) that provides the new interface.

Old clients can keep using the old class, new ones use the new version version. And of course, you annotate C as deprecated.

Lii
  • 11,553
  • 8
  • 64
  • 88
GhostCat
  • 137,827
  • 25
  • 176
  • 248
  • 1
    Hm... I think this would solve the concrete problem, with the cost of complicating the API with an additional class. And additional overloaded methods everywhere where `C` is an argument, in order to get the benefit of the type parameter. Hm. It will definitely not be worth it in my case. – Lii Mar 12 '17 at 15:11
  • Sure. Your points make sense. Maybe you should rather thinking about versioning your API as a whole then?! – GhostCat Mar 12 '17 at 15:19
  • Yeah, something like that could help ease the pain for the clients. Me myself think that the lazy clients should just have to update their code in order to get the benefit of the new version or the API. Maybe some kind of structured versioning scheme would help in making more people see it my way... – Lii Mar 12 '17 at 15:41