Xtra Coder
Xtra Coder

Reputation: 3497

Java generics & incompatible types: bug in compiler?

I've got "incompatible types" compiler error in condition not yet discussed in stackoverflow (e.g. Why won't this generic java code compile?).

My expectation is simple - I'm calling a templated method which does not use any 'generic' classes from containing class, therefore it should extract types of template parameters from method arguments and this should compile in all cases - but I get "incompatible types" compiler error.

I've noticed strange way to fix the problem - adding "< ? extends Data >" to generic datatype in method arguments. How does it change compiler logic?

In my understanding - there should be no difference because (1) DataContainer class' template parameters are not used in method call and (2) restriction "< TData extends Data >" already defines minimal base object class - Data - and therefore it should be automatically assumed when compiling template without arguments.

public void processData(DataContainer<? extends Data> c) {

(explicit type casting can be used, but i believe it is redundant here)

DummyContextClass dcc = (DummyContextClass)c.getContext(DummyContextClass.class);

Code for copy/paste

public class Test {

    public static class Data {
    }

    public static class DataContainer<TData extends Data> {
        public final TData Data;
        private final Map<String, Object> contexts = new HashMap<>();

        public DataContainer(TData data) {
            Data = data;
        }

        public <T> T getContext(Class<T> type) {
            return (T)contexts.get(type.getName());
        }

        public <T> void setContext(Class<T> type, T context) {
            contexts.put(type.getName(), context);
        }
    }

    public static class DummyContextClass {
    }

    public void processData(DataContainer c) {
        c.setContext(DummyContextClass.class, new DummyContextClass());

        // error: incompatible types: Object cannot be converted to DummyContextClass
        DummyContextClass dcc = c.getContext(DummyContextClass.class);
    }
}

Upvotes: 0

Views: 2209

Answers (1)

Bohemian
Bohemian

Reputation: 425368

The problem has nothing (much) to do with your generic methods.
Your problem is you are using a raw type as the parameter of your method:

public void processData(DataContainer c) { // Oops! DataContainer is a raw type

You should use a parameter with DataContainer:

public void processData(DataContainer<? extends Data> c) {

When you leave off the type of a generic class, you have what is called a raw type, and (due to compatibility requirements with old java versions), all generic information is stripped off the class. That (amongst other things) changes all return types that are declared as generic types into Object, so for compilation purposes, your method now looks like:

public Object getContext(Class type) {

...hence your error.

Upvotes: 6

Related Questions