Mad Max
Mad Max

Reputation: 79

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.

Upvotes: 0

Views: 690

Answers (1)

Michael
Michael

Reputation: 44250

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()
        );
    }
}

Upvotes: 4

Related Questions