Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why can the Oracle Java compiler not infer the bounds here but Eclipse can?

I have this (seemingly) innocent code (simplified into this JUnit test case here):

import static org.hamcrest.Matchers.instanceOf;
import static org.junit.Assert.assertThat;

import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.function.Supplier;

import org.junit.Test;

public class GenericsTest {
    private static boolean doFail;

    private static Map<String, Number> createMap() {
        if (doFail) {
            throw new IllegalArgumentException();
        }
        return new HashMap<>();
    }

    public static <T> T get(final Callable<T> _valueCreator, final Supplier<T> _errorValue) {
        try {
            return _valueCreator.call();
        } catch (final Exception e) {
            return _errorValue.get();
        }
    }

    public static Map<String, Number> getCachedMap() {
        return get(GenericsTest::createMap, Collections::emptyMap);
    }

    @Test
    public void testSuccess() {
        doFail = false;
        assertThat(getCachedMap(), instanceOf(HashMap.class));
    }

    @Test
    public void testFail() {
        doFail = true;
        assertThat(getCachedMap(), instanceOf(Collections.EMPTY_MAP.getClass()));
    }
}

The problem lies in the line return get(GenericsTest::createMap, Collections::emptyMap): the Eclipse compiler doesn't see a problem here (and so am I), happily compiles and runs the test and succeeds.

However, when I compile this on the command line (Maven 3, Oracle JDK8 in this case, but also doesn't work with javac directly), a compile error is thrown:

.../GenericsTest.java:[23,19] incompatible types: inferred type does not conform to upper bound(s)
inferred: java.util.Map<? extends java.lang.Object,? extends java.lang.Object>
upper bound(s): java.util.Map<java.lang.String,java.lang.Number>,java.lang.Object

I would think that from both the return type (Map<String, Number>) as well as from the signature of createMap (same) it should be possible to infer the required type - and in fact it seems that the Eclipse compiler seems to be able to do it. However, the JDK compiler only infers Map<Object, Object> and thus fails.

Is this a JDK bug or an Eclipse compiler bug or something else?

like image 633
Stefan Seidel Avatar asked Sep 26 '22 01:09

Stefan Seidel


1 Answers

This looks like a bug. I will take care of it and probably add a better answer once we have more information about why this is happening. I have filed this bug entry JDK-8043926 to track it.

like image 185
Abdelhak Avatar answered Sep 29 '22 00:09

Abdelhak