3

Possible Duplicate:
Is `List<Dog>` a subclass of `List<Animal>`? Why aren’t Java’s generics implicitly polymorphic?

I need help understanding whats going on.

I have an interface

public interface Foo {

  Map<String, ParameterValue> getParameters();
}

public interface ParameterValue { }

And an implementation of Foo.

class FooImpl implements Foo {
   Map<String, ParameterValueImpl> parameters = new HashMap<String, ParameterValueImpl>();
   //ParameterValueImpl an implementation of ParameterValue

@Override
    public Map<String, ParameterValue> getParameters() {
        return ((Map<String,ParameterValue>) parameters);
    }   

}

I get the following error

[ERROR] Failed to execute goal
failure [ERROR]
src/main/java/domainJPA/model/FooImpl.java:[92,45]
inconvertible types [ERROR] found   :
java.util.Map<java.lang.String,domainJPA.model.ParameterValueImpl>
[ERROR] required:
java.util.Map<java.lang.String,domain.model.ParameterValue>

I have to use the ParameterValue in the interface of Foo, and in FooImpl I must just the implementation of ParameterValue (ParameterValueImpl) because its an @Entity and jpa requires it.

How can I make this code compile?

EDIT

If I change the code to ? extends ParameterValue as suggested in one of the answers, then I cannot use the Foo interface.

The following code results in compilation error: The method put(String, capture#8-of ? extends ParameterValue) in the type Map<String,capture#8-of ? extends ParameterValue> is not applicable for the arguments (String, ParameterValueImpl)

foo.getParameters().put("test", new ParameterValueImpl);

Community
  • 1
  • 1
Shervin Asgari
  • 23,901
  • 30
  • 103
  • 143
  • http://stackoverflow.com/questions/2745265/is-listdog-a-subclass-of-listanimal-why-arent-javas-generics-implicit – assylias Nov 09 '12 at 15:49

2 Answers2

6

Think about it -- if the return value from getParameters() is actually a Map<String, ParameterValueImpl>, then you have the ability to add a value to the map that derives from ParameterValue, but not ParameterValueImpl. You would be breaking type safety by doing that.

You have two options to correct this:

  1. In getParameters(), copy the map into a new map of the correct type.
  2. Use Map<String, ParameterValue> as the type for FooImpl.parameters.
cdhowie
  • 158,093
  • 24
  • 286
  • 300
  • I can't do the second part as The FooImpl is an JPA entity, and If I use the interface, it will not recognize it. I didn't quite understand the 1 one. – Shervin Asgari Nov 09 '12 at 16:11
  • You may wind up having to make `Foo` a generic interface then, where the type parameter is used as the second type parameter to the map. – cdhowie Nov 09 '12 at 16:14
  • I understood the copy part, and I went for that instead. Seems to work for now. – Shervin Asgari Nov 09 '12 at 16:21
  • Beware though, since you are returning a copy, adding items to the map returned by this method will have *no effect* on the map contained in the `FooImpl` instance. Consider returning an read-only copy so that any attempt to modify the map will result in an error. – cdhowie Nov 09 '12 at 16:22
5

You can change your interface method to: -

Map<String, ? extends ParameterValue> getParameters();

Now, you can return a Map of String and any type implementing your ParameterValue

Then you dont' need a typecast in your implementation of this method.

public Map<String, ? extends ParameterValue> getParameters() {
    return parameters;
}   

Or, since you can store a ParameterValueImpl type instance in a ParameterType reference, so, you can also change the Map in your FooImpl class as: -

Map<String, ParameterValue> parameters = new HashMap<String, ParameterValue>();

then your original method will work.

Rohit Jain
  • 209,639
  • 45
  • 409
  • 525
  • If I use the `? extends ParameterValue` then the following code doesn`t compile: foo.getParameters().put("test", new ParameterValueImpl());` it gives me the error message `The method put(String, capture#8-of ? extends ParameterValue) in the type Map is not applicable for the arguments (String, ParameterValueImpl)` – Shervin Asgari Nov 09 '12 at 16:05
  • Well, you can't modify the Map if it is a type of `? extends Type`. Because you don't know what type you may actually insert. If you want to modify your Map. Then you should probably go with the 2nd way. – Rohit Jain Nov 09 '12 at 16:24