Search code examples
javaenumsannotations

Java enum implementing interface as custom annotation parameter


I'm creating an custom annotation with parameters. Parameters I want to use are enums that implement an interface. There are few enums that are candidates to b used as this annotation's parameter. Here are some code examples:

Interface:

public interface MyInterface {
    String getSomething();
    int getMore();
}

Enum example:

public enum MyEnum implements MyInterface {

    VAL1("some1", 1),
    VAL2("2val", 22);

    private String something;
    private int more;

    private MyEnum(String something, int more) {
        this.something = something;
        this.more = more;
    }

    public String getSomething() {
        return something;
    }

    public int getMore() {
        return more;
    }
}

I want to implement an annotation with parameter that can be retrieved as multiple MyInterface values. Let's say annotation looks like this:

@MyAnnotation(MyEnum.class)

or

@MyAnnotation(MyEnum.values())

So I can further retrieve it and pass it to a method that accepts Collection parameter.

How do I implement an annotation with a parameter so I can retrieve all values of enum as MyInterface type?

I was trying to do it like this:

public @interface MyAnnotation {
    Class<? extends Enum<?> & MyInterface> myValues();
}

So I could do:

Collection<MyInterface> desired = Arrays.asList(... .getAnnotation().myValues().enumValues());

but this syntax is invalid.


Solution

  • You can't use union types in an annotation member, so you'll have to give up on that idea.

    But frame challenge: why do you even care that the implementer has to be an enum?

    What I assume you care about is that something can give you a finite set of implementations. An enum is one way to achieve that, but why be overly restrictive if someone wants to give you a list of values some other way?

    I'd add a new interface which can provide a collection of values.

    interface MyInterfaceValueSource {
        List<MyInterface> values();
    }
    

    The enum gets a very simple implementation that just calls MyEnum.values().

    class MyEnumValueSource implements MyInterfaceValueSource {
        @Override
        public List<MyInterface> values() {
            return Arrays.asList(MyEnum.values());
        }
    }
    

    Your annotation can then be altered to accept one of those

    @interface MyAnnotation {
        Class<? extends MyInterfaceValueSource> value();
    }
    

    and example of its usage would be

    @MyAnnotation(MyEnumValueSource.class)
    

    Now if someone wants to provide a list of values but not implement it as an enum, they have the flexibility to do that.

    class ExampleValueSource implements MyInterfaceValueSource {
        @Override
        public List<MyInterface> values() {
            return Arrays.asList(
                new MyInterfaceOne(), new MyInterfaceTwo()
            );
        }
    }