In Eclipse Kepler 4.2 with jdk 1.7 I get following error in Eclipse:
The method or(capture#2-of ?) in the type Optional<capture#2-of ?> is not applicable for the arguments (Object)
whereas it compiles successfully when running mvn compile
.
The class looks following:
package testit;
import java.util.Map;
import java.util.Map.Entry;
import com.google.common.base.Optional;
public class Test {
private static final Object NO_VALUE = new Object();
public void method(Map<String, ?> map) {
for (Entry<String, ?> entry : map.entrySet()) {
Optional.fromNullable(entry.getValue()).or(NO_VALUE);
// ^^ error here
}
}
}
pom.xml:
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>my.test</groupId>
<artifactId>testit</artifactId>
<version>0.0.1-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>13.0.1</version>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.1</version>
<configuration>
<source>1.7</source>
<target>1.7</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
The similar code runs on production for a long while without errors (in this area). It is compiling in Maven, Jenkins, Intelij but not in Eclipse. Question is why it does not compile in Eclipse ?
After a deep analysis by the Eclipse Team (btw great thanks!) their answer on this problem is following
Quoted after Stephan Herrmann from Eclipse Bugzilla:
This line doesn't apply for the following reason:
Type inference starts by resolving this expression:
Optional.fromNullable(entry.getValue())
In this expression all elements can be typed as stated above:
entry : Entry entry.getValue:
capture#2-of ? fromNullable(..) : (capture#2-of ?) ->
Optional<capture#2-of ?>
In short: T is inferred to be "
capture#2-of ?
". Inference succeeds.Only after all these have been decided, does resolution proceed to inspect the .or(..) method call. No reason to fill in un-inferred inference variables with "Object".
With a receiver of type Optional, we have these three overloads of "or":
Optional or(Optional)
capture#2-of ? or(Supplier<? extends capture#2-of ?> supplier)
capture#2-of ? or(capture#2-of ? defaultValue)
None of these methods is applicable for an argument of type Object. ecj arbitrarily picks the first method for error reporting:
"The method or(Optional) in the type Optional is not applicable for the arguments (Object)"
The difference between ecj and javac is most certainly covered by the mentioned javac bug: https://bugs.openjdk.java.net/browse/JDK-8016207
As mentioned in that bug, a future update of the JLS may possibly adopt parts of the current javac behavior. Until such a spec update is released, the only reliable point of reference for ecj is the JLS. In this specification I see no reason for changing the behavior of ecj in this regard.
BTW, the canonical fix (no cast needed) is:
Optional.<Object>fromNullable(entry.getValue()).or(NO_VALUE);
For now that would be the conclusion.
Eclipse compiler is not the standard javac. It uses the ECJ Compiler This is definitely a bug in the Eclipse Compiler, as maven uses the standard javac to compile that's why it's working.
You didn't state a question so I assume the question: "Who is right, and how to make the code work?"
I'd say Eclipse is right.
The result of fromNullable
has Type parameter ?
, i.e. there exists a type T
but we don't know it.
The Optional
returned by or
must have the same type parameter as the Optional
it is called on, which also means it takes the same unknown type T
as a parameter. But Object
might or might not be compatible to that type, so it is correct to fail.
In order to fix it, I think the following change should work:
Optional.fromNullable((Object)entry.getValue()).or(NO_VALUE);
The cast binds the otherwise unknown type parameter to Object
which obviously is compatible to Object
in the call to or
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With