Java: Unable to use EnumSet within an Enumeration : Initialization error : Tech Research Talent Tree example
casting, enums, initialization, java
Solution
Your declaration structure is so clever it's a shame it doesn't work. But `EnumSet` apparently needs the enum to be fully initialized first. It tries to fetch the array of constants from the enum so that, among other things, it knows how much space is needed for its internal bitset.
Here's one workaround. It uses a helper method that creates an ordinary set (`HashSet`) first, and then, in a static initialization block, it iterates the enum constants and replaces all the sets with `EnumSet`s.
public enum BuildingTechTree {
// Named constants
//Name SoftName Requirements
NONE ("NULL", null),
BARRACKS ("Barracks", setOf(NONE)),
WALLS_SANDBAGS ("Sandbag wall", setOf(NONE)),
POWERPLANT ("Power plant", setOf(BARRACKS)),
GUARDTOWER ("Guard Tower", setOf(BARRACKS));
private final String softName;
private Set<BuildingTechTree> requirements;
private BuildingTechTree(String softName, Set<BuildingTechTree> requirements) {
this.softName = softName;
this.requirements = requirements;
}
private static Set<BuildingTechTree> setOf(BuildingTechTree... values) {
return new HashSet<>(Arrays.asList(values));
}
static {
for (BuildingTechTree v : values()) {
if (v.requirements == null) {
v.requirements = EnumSet.noneOf(BuildingTechTree.class);
} else {
v.requirements = EnumSet.copyOf(v.requirements);
}
}
}
}
Problem
Error: ``` ... Caused by: java.lang.ExceptionInInitializerError ... Caused by: java.lang.ClassCastException: class com.evopulse.ds2150.TechTrees$BuildingTechTree not an enum at java.util.EnumSet.noneOf(Unknown Source) at java.util.EnumSet.of(Unknown Source) at com.evopulse.ds2150.TechTrees$BuildingTechTree.<clinit>(TechTrees.java:38) ``` Here is a snippet of my enumeration ``` public enum BuildingTechTree { //Name SoftName Requirements NONE ("NULL", null), ``` --> This next line is where it crashes ``` BARRACKS ("Barracks", EnumSet.of(NONE), WALLS_SANDBAGS ("Sandbag wall", EnumSet.of(NONE), POWERPLANT ("Power plant", EnumSet.of(BARRACKS)), GUARDTOWER ("Guard Tower", EnumSet.of(BARRACKS)); ``` Replacing EnumSet.of(NONE) and EnumSet.of(BARRACKS) with null, lets initialization work, but breaks my code, due to missing data structure... obviously, but I did it to test the rest of my code wasn't somehow the cause. Removing EnumSet.of(NONE) and replacing with just NONE, and the same for BARRACKS, and changing all related variables, constructor, and methods, that didn't work either... (and even couldn't use the contains.all, since is wasn't "applicable to my changed variable"... ) I extended this example, using the second implementation: https://gamedev.stackexchange.com/a/25652/48573 I also tried retracing my steps by copying the example verbatim. added ``` private static Set<BuildingTechTree> techsKnown; techsKnown = (BuildingTechTree.BIODOME); test = TechTrees.researchTech(techsKnown); ``` to another class to be called from for testing initialization. and had to change ``` public boolean researchTech(BuildingTechTree tech) { ``` to static This resulted in the same "in not an enum" error. I don't have any rep, to comment on his answer to point out the initialization error... Added info for both current answers, as both solutions cause the same new error: ``` public class TechTrees { private static Set<BuildingTechTree> techsKnown; public TechTrees() { techsKnown = EnumSet.of(BuildingTechTree.NONE); //Using this techsKnown = EnumSet.noneOf(BuildingTechTree.class); //Or this } public static boolean researchTech(BuildingTechTree tech) { if (techsKnown.containsAll(tech.requirements)) { //Causes null pointer return true; //exception @ techsKnown } return false; } ```