I would like to be able to indicate an enum type as an interface implementation and then load all enums as separate instances/implementations of the interface via the ServiceLoader
API. An example of this use case would be to allow downstream users of my API to specify custom values, but provide an enum with standard/common implementations. My interface only requires a String name()
, so any enum implements it already.
For example, the CopyOption
interface in the Java NIO APIs, with the provided StandardCopyOption
enum. Say I wanted to load all CopyOption
s, even new ones on the classpath along with the standards, to a single iterator via ServiceLoader
(or I'm open to other suggestions!)
I finally got it to work by wholesale copying ServiceLoader
and modifying it to try using getEnumConstants
when instantiation fails (the part in the try
is how it works currently and the part in the catch
is what I added/changed):
try {
S p = service.cast(c.newInstance());
providers.put(cn, p);
return p;
} catch (Throwable x) {
Object[] arr = c.getEnumConstants();
if (arr == null || arr.length == 0) {
fail(service, "Provider " + cn + " could not be instantiated", x);
}
List<S> list = new LinkedList<>();
for (Object o : arr) {
Enum<?> e = (Enum<?>) o;
S p = service.cast(e);
providers.put(cn + e.ordinal(), p);
list.add(p);
}
subiter = list.iterator();
return subiter.next();
}
I also added some code such that if subiter
exists and has next, it is iterated before moving on to the next class name.
My question is: Is there a better way?
In case the end use is not clear, this is now what's possible with the above modifications:
interface ImageType {
String name();
}
@AutoService(ImageType.class)
enum StandardImageType implements ImageType {
IMAGE,
VECTOR,
RASTER,
HANDWRITING,
ICON,
LOGO,
SEAL,
RULE,
BARCODE
}