3

I have a class named FamilyHistoryPersonModel that extends a class named PersonModel.

    MapValue mapValue = new MapValue("relatives",
            new GenericType<FamilyHistoryPersonModel>() {},
            new GenericType<List<FamilyHistoryPersonModel>>() {}  //error here
    );

Constructor:

    private MapValue(String pluralUrl, GenericType<? extends PersonModel> singleResultGenericType, GenericType<List<? extends PersonModel>> listResultGenericType) {
        this.pluralUrl = pluralUrl;
        this.singleResultGenericType = singleResultGenericType;
        this.listResultGenericType = listResultGenericType;
    }

Error:

cannot find symbol
symbol  : constructor MapValue(java.lang.String,<anonymous com.sun.jersey.api.client.GenericType<com.models.FamilyHistoryPersonModel>>,<anonymous com.sun.jersey.api.client.GenericType<java.util.List<com.models.FamilyHistoryPersonModel>>>)
location: class com.rest.v2.resource.CreatePersonModelIntegrationTest.MapValue

Why am I getting this error? How do I fix it? I don't want to change the constructor to accept GenericType<List<FamilyHistoryPersonModel>> listResultGenericType

I am using JDK 1.6

Daniel Kaplan
  • 62,768
  • 50
  • 234
  • 356

1 Answers1

5

Just as a List<Dog> is not a List<Animal> even if Animal subclasses Dog, a GenericType<List<FamilyHistoryPersonModel>> is not a GenericType<List<? extends PersonModel>>, even if a List<FamilyHistoryPersonModel> is a List<? extends PersonModel>.

The solution is to provide a wildcard at the top-level generic type parameter. In the MapValue constructor, change the parameter from

GenericType<List<? extends PersonModel>> listResultGenericType

to

GenericType<? extends List<? extends PersonModel>> listResultGenericType

I assume that you will also need to change the type of this.listResultGenericType to match.

rgettman
  • 176,041
  • 30
  • 275
  • 357
  • FYI - I think this was "fixed" in JDK8: [Difference of assignability with nested wildcards in Java 7/8 generics](http://stackoverflow.com/questions/24188824). – DaoWen Jul 21 '14 at 22:30
  • That works, but I don't get why I have to do it. Why isn't a `List` a `List`? – Daniel Kaplan Jul 21 '14 at 22:30
  • @tieTYT - *"That works, but I don't get why I have to do it. Why isn't a List a List?"* That's **exactly** what [my question](http://stackoverflow.com/questions/24188824) (linked to in my comment above) was asking. – DaoWen Jul 21 '14 at 22:31
  • 3
    @tieTYT Java generic types are invariant, where you're expecting them to be covariant. For more detail, please see [Is List a subclass of List? Why aren't Java's generics implicitly polymorphic?](http://stackoverflow.com/questions/2745265/is-listdog-a-subclass-of-listanimal-why-arent-javas-generics-implicitly-p). – rgettman Jul 21 '14 at 22:31
  • @rgettman ok that was helpful. That explains why they are not the same thing. But I still don't get why ` extends List extends PersonModel>>` fixes the problem. – Daniel Kaplan Jul 21 '14 at 22:40
  • Without that first `? extends`, then the generic type parameter for the inner `List` _must_ be `? extends PersonModel`, to match the paramter's generic type, because Java generics are invariant. To be able to substitute `FamilyHistoryPersonModel` in the generic type parameter for `List`, you must `? extends` on the `List`, for the same reason that you must use `List extends Animal>` to be able to supply a `List`. Without that `? extends`, then generic type parameter must match exactly, because of the invariance of generics here. – rgettman Jul 21 '14 at 22:44