I've made the following method that uses circular generic types in its signature.
private <U extends NameTranslation<T> & Autocompletable, T extends Polyonymous<U>> U createNameTranslationInstance(T parent, Language targetLanguage,
String translatedName, String translatedAutoSuggestionText) {
if (parent instanceof Organism organism) {
return (U) new OrganismCommonNameTranslation(organism, targetLanguage, translatedName, gardenerPlanet,
translatedAutoSuggestionText, SubmissionStatus.APPROVED);
} else if (parent instanceof LifeStage lifeStage) {
return (U) new LifeStageCommonNameTranslation(lifeStage, targetLanguage, translatedName, gardenerPlanet,
translatedAutoSuggestionText, SubmissionStatus.APPROVED);
}
throw new IllegalArgumentException("Unsupported parent type: " + parent.getClass().getName());
}
This method returns an object of type U
which extends a NameTranslation abstract class with generic type T
and also implements the interface Autocompletable
. Generic type T
is of a type that extends interface Polyonymous
with a generic type U
.
When I try to compile this it will throw a couple of java compiler errors for this method.
java: incompatible types: T cannot be converted to POJOs.TaxonomicPojos.Organism
java: incompatible types: POJOs.TaxonomicPojos.categorytranslations.OrganismCommonNameTranslation cannot be converted to U
java: incompatible types: T cannot be converted to POJOs.TaxonomicPojos.LifeStage
java: incompatible types: POJOs.TaxonomicPojos.categorytranslations.LifeStageCommonNameTranslation cannot be converted to U
But both Organism
and LifeStage
extend Polyonymous<>
and the associated CommonNameTranslation classes each extend NameTranslation and implement AutoCompletable
.
When I remove extends Polyonymous<U>
and thereby removing the circular reference everything compiles again. I've googled to see if circular generic dependencies aren't allowed in Java. But according to this SO answer circular generics are perfectly allowable.
It gets even weirder when I remove & Autocompletable
from the method signature instead of the extends Polyonymous
part. Now this method causes an internal java compiler error instead.
java: Compilation failed: internal java compiler error
This type of error can occur due to a variety of reasons, including incorrect syntax in the code, incorrect usage of Java language constructs, memory or disk space issues, or bugs in the Java compiler itself (source).
So what is it about this generic signature that causes compile issues?
Here are all the class definitions
public class Organism implements Polyonymous<OrganismCommonNameTranslation>{
}
public class LifeStage implements Polyonymous<LifeStageCommonNameTranslation>{
}
public class OrganismCommonNameTranslation extends NameTranslation<Organism> implements Autocompletable {
}
public class LifeStageCommonNameTranslation extends NameTranslation<LifeStage> implements Autocompletable {
}
public abstract class NameTranslation<T>{}
public interface Polyonymous<T>{}
public interface Autcompletable{}
EDIT: Here's my java version info
openjdk 20.0.2.1 2023-08-22
OpenJDK Runtime Environment Corretto-20.0.2.10.1 (build 20.0.2.1+10-FR)
OpenJDK 64-Bit Server VM Corretto-20.0.2.10.1 (build 20.0.2.1+10-FR, mixed mode, sharing)
EDIT 07/12/2023
The internal java error seems to be caused by the explicit cast to (U) in combination with circular generic references.
I think your code is ok theoretically, but it seem like compiler is not smart enough.
I modified your code a little to fool compiler and it run well. Here is the code:
I found that the compiler errors occur in these two part:
instance of
to judge a generic variable is specific typeI think it may be better if you remove
extends NameTranslation<T> & Autocompletable
in your code, because they seem useless.I still don't know the exact reason why the compiler throw those errors. But hope my answer could help you a little.