Reputation: 11
Disclaimer: not very strong with generics.
Lets say I have Enum like this:
public enum FirstEnum implements BaseEnum<FirstEnum> {
SOMETHING_1(Month.FEBRUARY, MZ_AUGUST, MZ_NOVEMBER),
SOMETHING_2(Month.JANUARY, MZ_APRIL, MZ_NOVEMBER);
private final Month month;
private final List<OtherEnum> otherEnumList;
FirstEnum(final Month month, final OtherEnum... otherEnumList) {
this.month = month;
this.otherEnumList = Arrays.asList(otherEnumList);
}
public static List<OtherEnum> getByMonth(final Month month) {
for (final FirstEnum firstEnum : FirstEnum.values()) {
if (month.equals(firstEnum.getMonth())) {
return firstEnum.getOtherEnumList();
}
}
return Collections.emptyList();
}
}
There is also a SecondEnum like this but it is not relevant right now. My problem is how to implement BaseEnum (I think it would be an Interface), where a getByMonth() method will be implemented using generics.
I am trying something like this (but it's not working at all):
public interface BaseEnum<T extends BaseEnum<T>> {
static List<OtherEnum> getByMonth(final Month month) {
for (final T firstEnum : T.values()) {
if (month.equals(firstEnum.getMonth())) {
return Arrays.asList(firstEnum.getOtherEnumList());
}
}
return Collections.emptyList();
}
}
Any help is appreciated!
Upvotes: 1
Views: 83
Reputation: 86223
This is as close as I can get.
public interface BaseEnum {
public Month getMonth();
public List<OtherEnum> getOtherEnumList();
public static List<OtherEnum> getByMonth(Class<? extends BaseEnum> enumClass, final Month month) {
for (final BaseEnum firstEnum : enumClass.getEnumConstants()) {
if (month.equals(firstEnum.getMonth())) {
return firstEnum.getOtherEnumList();
}
}
return Collections.emptyList();
}
}
We cannot take out the enum constants from an enum except either by using the enum’s concrete name, as in FirstEnum.values()
, or through Class.getEnumConstants()
. For your purpose we had wanted to be able to use generics as you said and declare <T extends Enum<T>>
and then do T.values()
. Because of type erasure this cannot work.
Therefore the caller needs to supply the enum class. The upside is that the interface needs not be generic. Call for example like this:
List<OtherEnum> list = BaseEnum.getByMonth(FirstEnum.class, Month.MAY);
I am sure that reflection would have been an alternative.
As an aside we may also implement your method with a stream operation if we like:
public static List<OtherEnum> getByMonth(Class<? extends BaseEnum> enumClass, final Month month) {
return Arrays.stream(enumClass.getEnumConstants())
.filter(e -> e.getMonth().equals(month))
.findAny()
.map(BaseEnum::getOtherEnumList)
.orElse(Collections.emptyList());
}
Link: Type Erasure in Java Explained | Baeldung
Upvotes: 1