Reputation: 1176
I have the below Java class (with nested classes/interfaces). When running the main
method from within Eclipse (Version: 2019-09 R (4.13.0)) I get the following output:
java.version: 1.8.0_241
PageA.m3() called
This is the command line used by Eclipse:
/Library/Java/JavaVirtualMachines/jdk1.8.0_241.jdk/Contents/Home/bin/java -agentlib:jdwp=transport=dt_socket,suspend=y,address=localhost:52180 -javaagent:/Users/*****/eclipse/java-2019-09/Eclipse.app/Contents/Eclipse/configuration/org.eclipse.osgi/222/0/.cp/lib/javaagent-shaded.jar -Dfile.encoding=UTF-8 -classpath <a-list-of-.jar-files> _play.PageTest
When running the same code from within Intellij (IDEA 2019.3.3 (Community Edition)) I get the following output:
src/main/java/_play/PageTest.java:13: error: reference to m1 is ambiguous
.m1(pageAorB -> ((SpecialPage<?>) pageAorB).m3());
^
both method m1(Consumer<T#1>) in Page and method m1(Consumer<T#2>) in AbstractPage match
where T#1,T#2 are type-variables:
T#1 extends Page<T#1> declared in interface Page
T#2 extends Page<T#2> declared in class AbstractPage
Why do I get this error in Intellij but not in Eclipse? Is there a way to solve this so it runs without error in Intellij?
Here is the Java class:
package _play;
import java.util.function.Consumer;
import java.util.function.Function;
public class PageTest {
public static void main(String[] args) {
System.out.println("java.version: " + System.getProperty("java.version"));
new PageC()
.m2(pageC -> (1 == 1 ? new PageA() : new PageB()))
.m1(pageAorB -> ((SpecialPage<?>) pageAorB).m3());
}
public static interface Page<T extends Page<T>> {
T m1(Consumer<T> c);
<R> R m2(Function<? super T, ? extends R> f);
}
public static abstract class AbstractPage<T extends Page<T>> implements Page<T>{
@Override
public T m1(Consumer<T> c){
c.accept(self());
return self();
}
@Override
public final <R> R m2(Function<? super T, ? extends R> f) {
return f.apply(self());
}
abstract protected T self();
}
public static interface SpecialPage<T extends Page<T>> extends Page<T> {
T m3();
}
public static class PageC extends AbstractPage<PageC> {
@Override
protected PageC self() {
return this;
}
}
public static class PageB extends AbstractPage<PageB> implements SpecialPage<PageB> {
@Override
public PageB m3() {
System.out.println("PageB.m3() called");
return this;
}
@Override
public PageB self() {
return this;
}
}
public static class PageA extends AbstractPage<PageA> implements SpecialPage<PageA> {
@Override
public PageA m3() {
System.out.println("PageA.m3() called");
return this;
}
@Override
public PageA self() {
return this;
}
}
}
EDIT In this case the Page interface and AbstractPage class are in a library that the client can't change. but the client should be able to extend the Page interface.
Upvotes: 2
Views: 575
Reputation: 34255
The question is, is the Eclipse compiler (ecj) of version 4.13 or javac
1.8.0_241 which is used by IntelliJ and Gradle by default right?
The error message of javac
says it's ambiguous because in AbstractPage
the type variable T
refers to the type variable of AbstractPage
(named T
) and also refers to the different type variable of Page
(also named T
). But in fact, both type variable refer to the same type, not because they are named the same, but because AbstractPage
implements Page<T>
. It is not ambiguous and javac
erroneously gives the compile error here.
As a workaround of this javac
bug you can do one of the following:
Rewrite the code in the main
method using a variable of SpecialPage<? extends Page<?>>
for the intermediate result so that javac
need not infer it:
SpecialPage<? extends Page<?>> pageAorB = new PageC().m2(pageC -> (1 == 1 ? new PageA() : new PageB()));
pageAorB.m1(specialPage -> ((SpecialPage<?>) specialPage).m3());
Upvotes: 1