actual argument ... cannot be converted to ... by method invocation conversion - java

I'm making a mod for the game Minecraft.
Using Eclipse all work fine, compilation is successfull and I can play the game using my created mod.
However when I compile my code using gradle, I get this error :
C:\Users\Alexandre\MCForge\ForgeCreeperHeal\debug\build\sources\main\java\fr\eyzox\dependencygraph\DependencyGraph.java:31: error: method buildIndex in class DataKeyProvider<K> cannot be applied to given types;
node.keyProvider.buildIndex(index, node);
^
required: Map<KEY,DependencyGraph<KEY,? extends IData<KEY>>.Node>,DependencyGraph<KEY,? extends IData<KEY>>.Node
found: Map<KEY,DependencyGraph<KEY,DATA>.Node>,DependencyGraph<KEY,DATA>.Node
reason: actual argument Map<KEY,DependencyGraph<KEY,DATA>.Node> cannot be converted to Map<KEY,DependencyGraph<KEY,? extends IData<KEY>>.Node> by method invocation conversion
where KEY,DATA,K are type-variables:
KEY extends Object declared in class DependencyGraph
DATA extends IData<KEY> declared in class DependencyGraph
K extends Object declared in class DataKeyProvider
I don't understand why it works on Eclipse but does not with gradle.
Maybe it is pur java's generics missunderstanding, but I doubt it because all works fine in Eclipse.
Is it the error from my side or should I looking for a gradle plugin bug ?
I'm a beginner in gradle.
Maybe source code and build.gradle are needed to understand my issue.
I've created a repo here : https://github.com/RedRelay/FCH_DEBUG
EDIT : It seems to be an issue related to Eclipse. I've just learn Eclipse has its own compiler, and it seems to allow this instead of standard javac.

Eclipse has its own compiler which allows it instead of the standard javac compiler. I've changed
protected abstract void buildIndex(final Map<K, DependencyGraph<K, ? extends IData<K>>.Node> index, final DependencyGraph<K, ? extends IData<K>>.Node theNode) throws DuplicateKeyException;
to
protected abstract <D extends IData<K>> void buildIndex(final Map<K, DependencyGraph<K, D>.Node> index, final DependencyGraph<K, D>.Node theNode) throws DuplicateKeyException;
and it works now.

Related

javac cannot compile upper bounded wildcard but Eclipse can

I am working with a code base that has relied on Eclipse for compilation until now. My objective is to compile it with javac (via ant) to simplify the build process. The project compiles without complaint in Eclipse (version 2019-12 (4.14.0)), but javac (OpenJDK, both versions 1.8.0_275 and 14.0.2) produces method ... cannot be applied to given types errors involving upper bounded wildcards.
Steps to reproduce
Note that the repository is 64 MB at time of writing:
git clone git#github.com:jamesdamillington/CRAFTY_Brazil.git
cd CRAFTY_Brazil && git checkout 550e88e
javac -Xdiags:verbose \
-classpath bin:lib/jts-1.13.jar:lib/MORe.jar:lib/ParMa.jar:lib/ModellingUtilities.jar:lib/log4j-1.2.17.jar:lib/repast.simphony.bin_and_src.jar \
src/org/volante/abm/agent/DefaultSocialLandUseAgent.java
Error message output:
src/org/volante/abm/agent/DefaultSocialLandUseAgent.java:166: error: method removeNode in interface MoreNetworkModifier<AgentType,EdgeType> cannot be applied to given types;
this.region.getNetworkService().removeNode(this.region.getNetwork(), this);
^
required: MoreNetwork<SocialAgent,CAP#1>,SocialAgent
found: MoreNetwork<SocialAgent,MoreEdge<SocialAgent>>,DefaultSocialLandUseAgent
reason: argument mismatch; MoreNetwork<SocialAgent,MoreEdge<SocialAgent>> cannot be converted to MoreNetwork<SocialAgent,CAP#1>
where AgentType,EdgeType are type-variables:
AgentType extends Object declared in interface MoreNetworkModifier
EdgeType extends MoreEdge<? super AgentType> declared in interface MoreNetworkModifier
where CAP#1 is a fresh type-variable:
CAP#1 extends MoreEdge<SocialAgent> from capture of ? extends MoreEdge<SocialAgent>
1 error
For completeness the method containing the offending line is:
public void die() {
if (this.region.getNetworkService() != null && this.region.getNetwork() != null) {
this.region.getNetworkService().removeNode(this.region.getNetwork(), this);
}
if (this.region.getGeography() != null
&& this.region.getGeography().getGeometry(this) != null) {
this.region.getGeography().move(this, null);
}
}
Analysis of error message
We're told the compiler found type MoreNetwork<SocialAgent,MoreEdge<SocialAgent>> where it required MoreNetwork<SocialAgent,CAP#1>.
This implies the inferred value of CAP#1 is incompatible with MoreEdge<SocialAgent>
However we're told CAP#1 extends MoreEdge<SocialAgent> from capture of ? extends MoreEdge<SocialAgent>
The Java documentation on Upper Bounded Wildcards states that
The upper bounded wildcard, <? extends Foo>, where Foo is any type, matches Foo and any subtype of Foo.
I cannot see why MoreEdge<SocialAgent> doesn't match <? extends MoreEdge<SocialAgent>>, and consequently cannot reconcile 2 and 3.
Efforts made to resolve the problem
While my objective is to compile for Java 8, I am aware that there have been bugs found in javac related to generics and wildcards in the past (see discussion around this answer). However, I find the same problem with both javac 1.8.0_275 and javac 14.0.2.
I also thought about whether some form of explicit cast might provide the compiler with sufficient hints. However I can't think what to change since the type of this.region.getNetwork() is reported as MoreNetwork<SocialAgent,MoreEdge<SocialAgent>> in the error message as expected.
Generalisation of the problem (EDIT)
#rzwitserloot rightly pointed out that I hadn't included enough information about the dependencies in the code above to properly debug. Copying all the dependencies (including some code from libraries I don't control) would get very messy so I have distilled the problem into a self-contained program that produces an analogous error.
import java.util.HashMap;
import java.util.Map;
import java.util.List;
import java.util.ArrayList;
public class UpperBoundNestedGenericsDemo {
public static void main(String[] args) {
MapContainerManagerBroken mapContainerManager = new MapContainerManagerBroken();
MapContainer<A, B<A>> mapContainer = new MapContainer<>();
mapContainerManager.setMapContainer(mapContainer);
Map<A, B<A>> aMap = new HashMap<>();
aMap.put(new A(), new B<A>());
mapContainerManager.getMapContainer().addMap(aMap);
mapContainerManager.getMapContainer().removeMap(aMap);
}
}
/**
* Analogue of Region
*/
class MapContainerManagerBroken {
private MapContainer<A, ? extends B<A>> mapContainer;
void setMapContainer(MapContainer<A, ? extends B<A>> mapContainer) {
this.mapContainer = mapContainer;
}
MapContainer<A, ? extends B<A>> getMapContainer() {
return this.mapContainer;
}
}
/**
* Analogue of MoreNetworkService
*/
class MapContainer<T1, T2> {
List<Map<T1, T2>> listOfMaps = new ArrayList<>();
void addMap(Map<T1, T2> map) {
listOfMaps.add(map);
}
boolean removeMap(Map<T1, T2> map) {
return listOfMaps.remove(map);
}
}
class A {
}
class B<T> {
}
This compiles in Eclipse, but upon compiling with
javac -Xdiags:verbose UpperBoundNestedGenericsDemo.java
produces the error message
UpperBoundNestedGenericsDemo.java:18: error: method addMap in class MapContainer<T1,T2> cannot be applied to given types;
mapContainerManager.getMapContainer().addMap(aMap);
^
required: Map<A,CAP#1>
found: Map<A,B<A>>
reason: argument mismatch; Map<A,B<A>> cannot be converted to Map<A,CAP#1>
where T1,T2 are type-variables:
T1 extends Object declared in class MapContainer
T2 extends Object declared in class MapContainer
where CAP#1 is a fresh type-variable:
CAP#1 extends B<A> from capture of ? extends B<A>
UpperBoundNestedGenericsDemo.java:19: error: method removeMap in class MapContainer<T1,T2> cannot be applied to given types;
mapContainerManager.getMapContainer().removeMap(aMap);
^
required: Map<A,CAP#1>
found: Map<A,B<A>>
reason: argument mismatch; Map<A,B<A>> cannot be converted to Map<A,CAP#1>
where T1,T2 are type-variables:
T1 extends Object declared in class MapContainer
T2 extends Object declared in class MapContainer
where CAP#1 is a fresh type-variable:
CAP#1 extends B<A> from capture of ? extends B<A>
2 errors
Partial solution
The program in the previous section can be modified such that it compiles under both Eclipse and javac by replacing MapContainerManagerBroken with
class MapContainerManagerNoWildcards {
private MapContainer<A, B<A>> mapContainer;
void setMapContainer(MapContainer<A, B<A>> mapContainer) {
this.mapContainer = mapContainer;
}
MapContainer<A, B<A>> getMapContainer() {
return this.mapContainer;
}
}
That is, by removing the wildcard type bounds for MapContainer. This solves the immediate practical problem, but limits the flexibility of MapContainerManagerNoWildcards compared to MapContainerManagerBroken. An alternative would be to make this class generic, e.g.
class MapContainerManagerFixedGeneric<T extends B<A>> {
private MapContainer<A, T> mapContainer;
void setMapContainer(MapContainer<A, T> mapContainer) {
this.mapContainer = mapContainer;
}
MapContainer<A, T> getMapContainer() {
return this.mapContainer;
}
}
However, this does not explain why the line mapContainerManager.getMapContainer().addMap(aMap) is a compiler error when mapContainerManager is a MapContainerManagerBroken (such as in the example program). Specifically, why is the preceding line an error, but the following compiles?
MapContainer<A, ? extends B<A>> mapContainer = new MapContainer<A, B<A>>();
You've misunderstood the rules on what ? extends means as far as type compatibility is concerned.
Any two occurrences of ? extends Number are not compatible with each other, nor is ? extends Number compatible with Number itself. Here is a trivial 'proof' of why that is:
List<Integer> ints = new ArrayList<Integer>();
List<? extends Number> numbers1 = ints; // legal
List<Number> numbers2 = numbers1; // legal?
numbers2.add(new Double(5.0)); // oh whoopsie
If the above compiles, then there is a non-int in ints, and that's no good. Fortunately, it doesn't compile. Specifically, the third line is a compiler error.
The segment of the JLS you are talking about is talking about a one-way street. You can assign a List<Number> to a variable of type List<? extends Number> (or pass a List<Number> as argument when the argument is of that type), but not the other way around.
? is the same as 'imagine I used a letter here and that I use this letter only here and nowhere else'. Thus, if you have two ? involved, they may not be equal to each other. Therefore, for type compatibility purposes, they aren't compatible. This makes sense; imagine you have:
void foo(List<? extends Number> a, List<? extends Number b>) {}
then it stands to reason that the point is that I can invoke this passing some List<Integer> for a and List<Double> for b: Each ? gets to be whatever it wants as long as it fits the bounds. Which also means that it is impossible to invoke add on either of these lists, as the thing you add must be of type ?, and you can't make that happen (except, trivially, by writing .add(null), as null is every type for such purposes), but that's not very useful). It also explains why you can't write a = b; and that goes to the heart of your problem here. Why can you not assign a to b? They are the same type, after all! - No, they are not, and that CAP stuff captures this: a is of type CAP#1 and b is of type CAP#2. That's how javac (and ecj, presumably) sort this out, and that's why this CAP stuff is showing up. It's not a matter of the compiler being intentionally dense or underspecced. It's inherent in the complexities of generics.
Thus, yes: CAP#1 is not the same as ? extends Number, it is merely one capture of that (and any further ? extends Number would then be referred to as CAP#2, and CAP#1 and CAP#2 are not compatible; one may be Integer and one may be Double, after all). The error message itself is sensible.
Normally if ecj and javac disagree, usually ecj is correct and javac is not, based on personal experience (I recount about 10 times I ran into a situation where ecj and javac disagreed, and 9 out of the 10 times, ecj was more correct than javac; though often it is an ambiguity in the JLS that I then report and which have been resolved). Nevertheless, given that JDK14 still has the issue, and trying to interpret these error messages (this is quite difficult without all the signatures involved here, you haven't pasted the useful parts of your codebase), it does look like javac is correct.
The usual fix is to toss more ? in there. In particular, a removeEdge sure sounds like it should accept either Object or ? extends T and not T. After all, arraylist's .remove() method accepts any object, not a T - trying to remove some double from a list of ints simply doesn't do anything, as per spec: Asking a list to remove a thing that isn't inside is a noop. No reason to limit the parameter, then. That solves many problems right there.
EDIT, after you've significantly updated your question with way more detail.
MapContainer<A, ? extends B> mapContainer = new MapContainer<A, B>();
Because that's what that means. Remember, MapContainer<? extends Number> does not represent a type. It represents a whole dimension worth of types. It's saying that mapContainer is a reference that can point at almost anything, as long as it is a MapContainer, of any 'tag' (the stuff in the <> you please, long as the thing that is in between is either Number or any subtype thereof. The only methods you can invoke on this exploded 'could be so many things' type is what ALL possible things it could be have in command, and no addMap method of any stripe is a part of the intersection. The addMap method's parameter involves an A, as in, in this example, the same thing as ? extends Number and the compiler says: Well, I don't know. There is no type that fits. I can't go with Number; what if you have a MapContainer<Integer>? If I let you call addMap using any Number, you could put a Double in there, and that's not allowed. The fact that eclipse allows it at all is bizarre.
Here is a borderline trivial example:
Map<? extends Number, String> x = ...;
x.put(A, B);
In the above example, nothing can be written on either the 3 dots, or in place of A to make that ever compile. ? extends is shorthand for: No add/put. Period.
There is actually one thing that will work: x.put(null, B);, because null 'fits' every type. But this is a copout and not at all useful for serious code.
Once you fully grok this, the problem is explained. More generally, given that you have a MapContainer<? extends something>, you can't call addMap on that thing. Period. You can't call 'write' operations on extends style typebounds.
I've explained why that is at the very top of this answer.

Code compiles in Eclipse but not javac: curried lambdas with functional subinterface. Which is correct?

I developed some code in Eclipse, tested it successfully, pushed it to our Jenkins CI server, and got an email that Maven was choking with a Java compile error. I subsequently isolated the problem and created the following minimal example showing the issue:
import java.util.List;
import java.util.function.Function;
class MinimalTypeFailureExample {
public static void main(String[] args) {
List<String> originalList = null; // irrelevant
List<IntToByteFunction> resultList = transform(originalList,
outer -> inner -> doStuff(inner, outer));
System.out.println(resultList);
}
static <F, T> List<T> transform(List<F> originalList,
MyFunction<? super F, ? extends T> function) {
return null; // irrelevant
}
static Byte doStuff(Integer inner, String outer) {
return null; // irrelevant
}
}
#FunctionalInterface
interface MyFunction<F, T> extends Function<F, T> {
#Override
T apply(F input);
}
#FunctionalInterface
interface IntToByteFunction {
Byte applyIntToByte(Integer inner);
}
In Eclipse, this code compiles without error and appears to execute as intended. However, compiling with javac gives the following error:
MinimalTypeFailureExample.java:7: error: incompatible types: cannot infer type-variable(s) F,T
List<IntToByteFunction> resultList = transform(originalList, outer -> inner -> doStuff(inner, outer));
^
(argument mismatch; bad return type in lambda expression
T is not a functional interface)
where F,T are type-variables:
F extends Object declared in method <F,T>transform(List<F>,MyFunction<F,? extends T>)
T extends Object declared in method <F,T>transform(List<F>,MyFunction<F,? extends T>)
1 error
Changing the argument type of transform() from MyFunction to Function, or removing the wildcard ? extends in the argument type, makes the example code compile in javac.
Clearly, either Eclipse or javac is in violation of the Java Language Specification. The question is, do I file the bug report on Eclipse or javac? The type inference rules for generic lambdas are so complex that I have no idea whether this program is legal Java or not according to the JLS.
Motivation note
In the original code, transform() was Guava's com.google.common.collect.Lists.transform(). The MyFunction interface was Guava 's com.google.common.base.Function interface, which extends java.util.function.Function for historical reasons.
The purpose of this code was to create a view of a list of a first type as a list of a second type. The second type was a functional interface type and I wanted to populate the output list with functions of this type constructed based on the values in the input list—hence the curried lambda expression.
Version info for reproducibility
Eclipse versions tested:
2018-09 (4.9.0) Build id: 20180917-1800
2019-03 RC1 (4.11 RC1) Build id: 20190307-2044
javac versions tested:
1.8.0_121
JDK 10.0.1 via the JDoodle online Java compiler
It looks like you run into JDK bug JDK-8156954 which has been fixed in Java 9 but not in Java 8.
It is a bug of Java 8 javac because in your example all variable types of the transform method can be inferred without violating the Java language specification as follows:
F: String (via first parameter originalList of type List<String>)
T: IntToByteFunction (via return type List<IntToByteFunction>)
These inferred variable types are compatible with the type of the second parameter, the chained lambda expression:
outer -> inner -> doStuff(inner, outer) resolves (with doStuff(Integer, String) to
String -> Integer -> doStuff(Integer, String) resolves to
String -> Integer -> Byte is compatible with
String -> IntToByteFunction is compatible with
MyFunction<? super String, ? extends IntToByteFunction>
Your example can be minimized further:
import java.util.function.Function;
class MinimalTypeFailureExample {
void foo() {
transform((Function<Integer, String>)null, o -> i -> {return "";});
}
<T, F> void transform(F f, MyFunction<T, ? extends F> m) {}
}
#FunctionalInterface
interface MyFunction<T, R> extends Function<T, R> {
#Override
R apply(T t);
}
MyFunction overrides the same with the same (R apply(T t);). If Function instead of MyFunction is used or if MyFunction extends Function but without #Override R apply(T t); then the error disappears. Also with F instead of ? extends F the error disappears.
Even if your example differs from the example in the mentioned bug, it can be assumed that it is the same bug because it is the only "argument mismatch; bad return type in lambda expression bug that has been fixed in Java 9 but not in Java 8 and that occurs only with lambda functions in combination with Java Generics.
I tried the example code with javac 11.0.2 and received no error. That would suggest that the bug may have been in javac and is fixed in recent versions. I am slightly surprised at this because as mentioned I did try testing JDK 10 in an online interface.
I am open to other answers that provide more details on the specific problem, such as a JDK bug number for the issue.
As a workaround to make the code compile in JDK 8, an explicit cast can be added to the inner lambda expression:
List<IntToByteFunction> resultList = transform(originalList,
outer -> (IntToByteFunction) inner -> doStuff(inner, outer));

IntelliJ Idea can not resolve same method in super class and interface

Here i'm reading spring-security-oauth2 source code and found there was a compile error in AuthorizationServerSecurityConfigurer.
below is the capture of such error:
this is errors Idea gives : Ambiguous method call: both AbstractConfiguredSecurityBuilder.getConfigurer(..) and HttpSecurityBuilder matches
But i know abstract class can implements methods both exists in its super class and interface in Java. but Idea do not know, how can i remove such error hint(having obsession about such red color).
At last, this is the hierarchy generated by Idea about class AuthorizationServerSecurityConfigurer:

Java generics compilation error "incompatible types" (in gradle but not in IDE)

I have a problem understanding the behaviour of Java generics in the following case.
Having some parametrised interface, IFace<T>, and a method on some class that returns a class extending this interface, <C extends IFace<?>> Class<C> getClazz() a java compilation error is produced by gradle, 1.8 Oracle JDK, OSX and Linux, but not by the Eclipse compiler within the Eclipse IDE (it also happily runs under Eclipse RCP OSGi runtime), for the following implementation:
public class Whatever {
public interface IFace<T> {}
#SuppressWarnings("unchecked")
protected <C extends IFace<?>> Class<C> getClazz() {
return (Class<C>) IFace.class;
}
}
➜ ./gradlew build
:compileJava
/Users/user/src/test/src/main/java/Whatever.java:6: error: incompatible types: Class<IFace> cannot be converted to Class<C>
return (Class<C>) IFace.class;
^
where C is a type-variable:
C extends IFace<?> declared in method <C>getClazz()
1 error
:compileJava FAILED
This implementation is not a very logical one, it is the default one that somebody thought was good, but I would like to understand why it is not compiling rather than question the logic of the code.
The easiest fix was to drop a part of the generic definition in the method signature. The following compiles without issues, but relies on a raw type:
protected Class<? extends IFace> getClazz() {
return IFace.class;
}
Why would this compile and the above not? Is there a way to avoid using the raw type?
It's not compiling because it's not type-correct.
Consider the following:
class Something implements IFace<String> {}
Class<Something> clazz = new Whatever().getClazz();
Something sth = clazz.newInstance();
This would fail with a InstantiationException, because clazz is IFace.class, and so it can't be instantiated; it's not Something.class, which could be instantied.
Ideone demo
But the non-instantiability isn't the relevant point here - it is fine for a Class to be non-instantiable - it is that this code has tried to instantiate it.
Class<T> has a method T newInstance(), which must either return a T, if it completes successfully, or throw an exception.
If the clazz.newInstance() call above did succeed (and the compiler doesn't know that it won't), the returned value would be an instance of IFace, not Something, and so the assignment would fail with a ClassCastException.
You can demonstrate this by changing IFace to be instantiable:
class IFace<T> {}
class Something extends IFace<String> {}
Class<Something> clazz = new Whatever().getClazz();
Something sth = clazz.newInstance(); // ClassCastException
Ideone demo
By raising an error like it does, the compiler is removing the potential for getting into this situation at all.
So, please don't try to fudge the compiler's errors away with raw types. It's telling you there is a problem, and you should fix it properly. Exactly what the fix looks like depends upon what you actually use the return value of Whatever.getClass() for.
It is kind of funny, that the Eclipse compiler does compile the code, but Oracle Java Compiler will not compile it. You can use the Eclipse Compiler during the gradle build to make sure, gradle is compiling the same way the IDE does. Add the following snippet to your build.gradle file
configurations {
ecj
}
dependencies {
ecj 'org.eclipse.jdt.core.compiler:ecj:4.4.2'
}
compileJava {
options.fork = true
options.forkOptions.with {
executable = 'java'
jvmArgs = ['-classpath', project.configurations.ecj.asPath, 'org.eclipse.jdt.internal.compiler.batch.Main', '-nowarn']
}
}
It fails to compile because C could possibly be anything, where the compiler can be sure that IFace.class does not fulfill that requirement:
class X implements IFace<String> {
}
Class<X> myX = myWhatever.getClass(); // would be bad because IFace.class is not a Class<X>.
Andy just demonstrated why this assignment would be bad (e.g. when trying to instantiate that class), so my answer is not very different from his, but perhaps a little easier to understand...
This is all about the nice Java compiler feature of the type parameters for methods implied by calling context. You surely know the method
Collections.emptyList();
Which is declared as
public static <T> List<T> emptyList() {
// ...
}
An implementation returning (List<T>)new ArrayList<String>(); would obviously be illegal, even with SuppressWarnings, as the T may be anything the caller assigns (or uses) the method's result to (type inference). But this is very similar to what you try when returning IFace.class where another class would be required by the caller.
Oh, and for the ones really enjoying Generics, here is the possibly worst solution to your problem:
public <C extends IFace<?>> Class<? super C> getClazz() {
return IFace.class;
}
Following will probably work:
public class Whatever {
public interface IFace<T> {}
#SuppressWarnings("unchecked")
protected <C extends IFace> Class<C> getClazz() {
return (Class<C>) IFace.class;
}
}
In your former code, problem is that C has to extend IFace<?>>, but you provided only IFace. And for type system Class<IFace> != Class<IFace<?>>, therefore Class<IFace> can not be cast to Class<C extends IFace<?>>.
Maybe some better solution exists, as I am not a generics expert.

Incompatible nullness constraints in java class hierarchy with generics

I am in the middle of migrating my java codebase for a project from java7 to java8. In the process I am also switching from the javax.annotation #Nullable, #NonNull and #ParametersAreNotNullByDefault annotations to the org.eclipse.jdt annotations for null-analysis in eclipse (Mars Release 4.5.0:Build id: 20150621-1200).
In doing this, I stumbled upon a situation where I can't compile (because of strict eclipse settings with regard to annotation based null checking) because of something I can't explain. I am not looking to find a way to compile my code, but more to understand why the error is occurring.
I have the following classes in a package specifying default non nullness using #NonNullByDefault in a package-info.java.
I have an interface implemented by an abstract class which is in turn extended by a concrete class as follows:
public interface SimulationComponent {
<T extends SimulationComponent> List<T> getCorrectSimulationSubComponents();
List<? extends SimulationComponent> getErroneousSimulationSubComponents();
}
public abstract class AbstractSimulationComponent
implements SimulationComponent {
#Override
public List<SimulationComponent> getCorrectSimulationSubComponents() {
return Collections.emptyList();
}
#Override
public List<SimulationComponent> getErroneousSimulationSubComponents() {
return Collections.emptyList();
}
}
public class ConcreteSubSimComponent extends AbstractSimulationComponent {
public void doSomething() {
}
}
Eclipse notifies me of the following problem in ConcreteSubSimComponent:
The method #NonNull List<#NonNull SimulationComponent> getErroneousSimulationSubComponents() from
AbstractSimulationComponent cannot implement the corresponding method from SimulationComponent due
to incompatible nullness constraints
This problem seems to be caused by the generics wildcard in getErroneousSimulationSubComponents(). This is how I specified the method that resulted in me noticing the problem when migrating to java8.
I figured out that I could 'easily' fix things by just replacing this method signature to the one shown in getCorrectSimulationSubComponents().
I don't see why this last version works and the previous version doesn't.
Also, this only seems to be a problem in the concrete subclass. A concrete class directly implementing the interface does not show any problems.
I am using JavaSE-1.8 and an example project with the code that does not compile, can be found at https://github.com/KrisC369/NullProblemIllustration
Apparantly, this bug has been resolved by the changes introduced to fix bug 436091 against JDT-core.
This fix should be present in eclipse Mars.2 (4.5.2) and eclipse neon-M4 (4.6.0-M4).

Categories