Question

Consider that I have an interface com.mycompany.SomeInterface, and an enum com.mycompany.SomeEnum implements SomeInterface. I want to get all enum constants of this class – as instances of SomeInterface – at runtime using the Reflection API.

Currently, my code (in the class EnumConstantGetter) is something like this:

Class<?> clazz = EnumConstantGetter.class.getClassLoader().
  loadClass("com.mycompany.SomeEnum");

if (!(SomeInterface.class.isAssignableFrom(clazz)) {
    throw new Exception("the class doesn't implement SomeInterface");
}

if (!(clazz.isEnum()) {
    throw new Exception("not an enum");
} 

Class<? extends Enum<? extends SomeInterface>> castClass =
  (Class<? extends Enum<? extends SomeInterface>>) clazz; // cast #1
ArrayList<SomeInterface> vals = new ArrayList<SomeInterface>();
for (Enum<? extends SomeInterface> enumConstant :
  castClass.getEnumConstants()) {
    vals.add((SomeInterface) enumConstant); // cast #2
}

The above code appears to work, but I get a compiler warning at the creation of castClass.

My question, then, is: are both casts noted in the code (the cast on the class and the cast on the constant) necessarily valid based on my checks?

In other words, is every member of Enum<? extends T> guaranteed to implement T?

If the answer is, "Yes, the casts are safe," then why does the compiler give me this warning?

If not, why not? or, in what circumstances could the routine fail?

EDIT: As my code above is apparently confusing, here's my explanation of what's supposed to be happening:

  1. Load the class named SomeEnum in the package com.mycompany and store its Class object in a variable.
  2. Ensure that the referenced class implements the SomeInterface interface.
  3. Ensure that the referenced class is an enum.
  4. As we know that it's an enum implementing SomeInterface, cast it to a Class<? extends Enum<? extends SomeInterface>> – cast #1
  5. Loop through all the enum constants.
  6. For each constant, cast it to a SomeInterface – cast #2 – and add it to the list of constants.

Thanks!

Was it helpful?

Solution

You could do the following:

Class<?> clazz = ...;
Class<? extends SomeInterface> someInterfaceClass;
try {
    someInterfaceClass = clazz.asSubclass(SomeInterface.class);
}
catch (ClassCastException cce) {
    throw new IllegalStateException("Specified type doesn't implement SomeInterface", cce);
}
SomeInterface[] enumConstants = someInterfaceClass.getEnumConstants();
if (enumConstants == null) {
    throw new IllegalStateException("Specified type is not an enum.");
}

//use constants

This avoids the warnings because asSubclass is checked and getEnumConstants returns null if the Class object "does not represent an enum type".

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top