Get enum constant from #JsonProperty value - java

I have an Enum marked with #JsonProperty for JSON serialization/deserialization with Jackson and would like to get the enum value for a given String JsonProperty:
public enum TimeBucket {
#JsonProperty("Daily") DAY_BUCKET,
#JsonProperty("Weekly") WEEK_BUCKET,
#JsonProperty("Monthly") MONTH_BUCKET;
}
The desired method should be generic/static (so it would not be necessary to replicate it in each of the enums) and would extract an enum value out of one of the JsonProperties:
public static <T extends Enum<T>> T getEnumFromJsonProperty(Class<T> enumClass, String jsonPropertyValue)

The desired result can be achieved through the following method:
public static <T extends Enum<T>> T getEnumValueFromJsonProperty(Class<T> enumClass, String jsonPropertyValue) {
Field[] fields = enumClass.getFields();
for (int i=0; i<fields.length; i++) {
if (fields[i].getAnnotation(JsonProperty.class).value().equals(jsonPropertyValue)) {
return Enum.valueOf(enumClass, fields[i].getName());
}
}
return null;
}

Related

How can I remove the duplicate source code with enum and generic in Java?

I would like to delete the duplicate source code below.
public static List<Map<String, Object>> getTransmissionTypeList() {
List<Map<String, Object>> transmissionList = new ArrayList<>();
for(EstimateTransmissionType transmissionType : EstimateTransmissionType.values()) {
Map<String, Object> transmission = new HashMap<>();
transmission.put("code", transmissionType.getCode());
transmission.put("value", transmissionType.getValue());
transmission.put("name", transmissionType.getName());
transmissionList.add(transmission);
}
return transmissionList;
}
public static List<Map<String, Object>> getFuelTypeList() {
List<Map<String, Object>> fuelList = new ArrayList<>();
for(EstimateFuelType fuelType : EstimateFuelType.values()) {
Map<String, Object> transmission = new HashMap<>();
transmission.put("code", fuelType.getCode());
transmission.put("value", fuelType.getValue());
transmission.put("name", fuelType.getName());
fuelList.add(transmission);
}
return fuelList;
}
For the EstimateTransmissionType and EstimateFuelType, those two enums are totally same structure inside.
public enum EstimateTransmissionType {
AUTO("오토(A/T)", "A001", "001"),
MANUAL("수동(M/T)", "A002", "002"),
ETC("기타", "A999", "999");
final String name;
final String value;
final String code;
EstimateTransmissionType(String name, String value, String code) {
this.name = name;
this.value = value;
this.code = code;
}
public String getName() {
return name;
}
public String getValue() {
return value;
}
public String getCode() {
return code;
}
}
public enum EstimateFuelType {
GASOLINE("가솔린", "A001", "001"),
DIESEL("디젤", "A002", "002"),
LPG_GENERAL("LPG(일반인 구입)", "A003", "003"),
LPG_ALL("LPG", "A004", "004"),
HYBRID("가솔린+전기", "A005", "005"),
ELECTRONIC("전기", "A009", "009"),
ETC("기타", "A999", "999");
final String name;
final String value;
final String code;
EstimateFuelType(String name, String value, String code) {
this.name = name;
this.value = value;
this.code = code;
}
public String getName() {
return name;
}
public String getValue() {
return value;
}
public String getCode() {
return code;
}
}
I really want to improve my source code quality, but I have no idea where to start this.
Could somebody give me a good inspiration or clear answer?
The new old wisdom to prefer composition over inheritance seems to apply here. We can do all the common stuff in a delegate class:
import java.util.Arrays;
import java.util.Map;
import java.util.HashMap;
import java.util.List;
import java.util.stream.Collectors;
public class EnumDemo {
interface AttributeProvider {
EstimateAttributes getAttributes();
}
public enum EstimateTransmissionType implements AttributeProvider {
AUTO("오토(A/T)", "A001", "001"),
MANUAL("수동(M/T)", "A002", "002"),
ETC("기타", "A999", "999");
private final final EstimateAttributes attributes;
EstimateTransmissionType(String name, String value, String code) {
this.attributes = new EstimateAttributes(name, value, code);
}
#Override
public EstimateAttributes getAttributes() {
return attributes;
}
}
public enum EstimateFuelType implements AttributeProvider {
GASOLINE("가솔린", "A001", "001"),
DIESEL("디젤", "A002", "002"),
LPG_GENERAL("LPG(일반인 구입)", "A003", "003"),
LPG_ALL("LPG", "A004", "004"),
HYBRID("가솔린+전기", "A005", "005"),
ELECTRONIC("전기", "A009", "009"),
ETC("기타", "A999", "999");
private final EstimateAttributes attributes;
EstimateFuelType(String name, String value, String code) {
attributes = new EstimateAttributes(name, value, code);
}
#Override
public EstimateAttributes getAttributes() {
return attributes;
}
}
static class EstimateAttributes {
private final String name;
private final String value;
private final String code;
public EstimateAttributes(String name, String value, String code) {
this.name = name;
this.value = value;
this.code = code;
}
public Map<String, Object> asMap() {
Map<String, Object> map = new HashMap<>();
map.put("name", name);
map.put("value", value);
map.put("code", code);
return map;
}
// Add getters if needed.
}
public static <E extends Enum<E> & AttributeProvider>
List<Map<String, Object>> getAttributeMaps(Class<E> enumClass) {
return Arrays.stream(enumClass.getEnumConstants())
.map(enumValue -> enumValue.getAttributes().asMap())
.collect(Collectors.toList());
}
}
Now we can say EnumDemo.getAttributeMaps(EstimateTransmissionType.class) and EnumDemo.getAttributeMaps(EstimateFuelType.class).
This answer is related and helpful -- https://stackoverflow.com/a/70596442/10118965
But here is a more directed answer. In short, using interfaces, enums, and generics allows you to make this much easier to consolidate.
First, create an interface that has all of the relevant functions. I called mine ParentInterface. In this case, you needed ::getName, ::getValue, and ::getCode.
Next, you need to create a method inside that interface that returns the values of the enum. This is a more complicated step because it requires you to take a pretty big step into the generics world, combined with enums.
In short, if we look at the JavaDoc for enums, we see the following.
https://docs.oracle.com/en/java/javase/19/docs/api/java.base/java/lang/Enum.html
Class Enum<E extends Enum<E>>
So in short, if we want to say that some type E is an enum, then we must say something like this.
E extends Enum<E>
Ok, now we know how to say that the parameterized type must be an enum. The reason why we did this is because we actually wanted to get the values of the enum. We can't do that without first making sure that we have an enum.
But now that we do, we can write a method sort of like this.
public static <E extends Enum<E>> List<E> values(final Class<E> clazz)
{
return Arrays.asList(clazz.getEnumConstants());
}
This method says that the clazz that we receive as a paramter must be a type of enum. Once it proves that, then we can safely call the Class::getEnumConstants method and be sure that we will get what we expect.
So, now that we have wrote our static method, next we put a parameterized type on the interface. Specifically, we want to make sure that this interface only refers to enums.
We add the following parameterized type to the interface.
<E extends Enum<E>>
And then finally, we modify our static method just slightly to make sure that it is only used to generate enum values for enums that implement our interface. Maybe you don't want that restriction, but in case you do, here is what you would add.
& ParentInterface<E>
And with that, we are done. Here is what our interface should roughly look like.
public interface ParentInterface<E extends Enum<E>> // pick a better name
{
String getName();
String getValue();
String getCode();
public static <E extends Enum<E> & ParentInterface<E>> List<E> values(final Class<E> clazz)
{
return Arrays.asList(clazz.getEnumConstants());
}
}
Next, we need to make sure all of our enums implement this new interface. That is pretty easy to do.
public enum EstimateFuelType implements ParentInterface<EstimateFuelType>
public enum EstimateTransmissionType implements ParentInterface<EstimateTransmissionType>
The actual internals of the enum shouldn't have to change. All you are doing is changing the outside.
And then finally, let us rework our method to handle this brand new interface and our reworked enums.
Let's start by building off of our ::getFuelTypeList method. That means that we start with a duplicate, but renamed.
public static List<Map<String, Object>> getGenericTypeList() {
List<Map<String, Object>> fuelList = new ArrayList<>();
for(EstimateFuelType fuelType : EstimateFuelType.values()) {
Map<String, Object> transmission = new HashMap<>();
transmission.put("code", fuelType.getCode());
transmission.put("value", fuelType.getValue());
transmission.put("name", fuelType.getName());
fuelList.add(transmission);
}
return fuelList;
}
Other than the method name, this method is exactly the same as ::getFuelTypeList.
Let's start by changing the method signature to include the generics that we made. More specifically, let's introduce this method to the idea of our interface.
public static <E extends ParentInterface<E>> List<Map<String, Object>> getGenericTypeList()
However, if we try to do just this, the compiler will complain at us, saying that if we want E to extend our interface, it must also extend Enum<E> too. Otherwise, it will break the rule of our interface, which says that "Anything that extends me must have an enum in the type parameter that also extends me". We made this rule earlier on when putting the type parameter on our interface.
So, to get past this, we must specify that our type parameter also is an enum. That is easy enough to change.
public static <E extends Enum<E> & ParentInterface<E>> List<Map<String, Object>> getGenericTypeList()
Now, the compiler is happy.
So, because of this change, our method is now aware of a type called E. This type is a subtype of an enum, and is also a subtype of the interface that we made.
Now that the method is aware of our type, let's actually put it to use. Here is what we have thus far.
public static <E extends Enum<E> & ParentInterface<E>> List<Map<String, Object>> getGenericTypeList() {
List<Map<String, Object>> fuelList = new ArrayList<>();
for(EstimateFuelType fuelType : EstimateFuelType.values()) {
Map<String, Object> transmission = new HashMap<>();
transmission.put("code", fuelType.getCode());
transmission.put("value", fuelType.getValue());
transmission.put("name", fuelType.getName());
fuelList.add(transmission);
}
return fuelList;
}
Obviously, everything is still hardcoded to use EstimateFuelType. So let's start by changing that.
public static <E extends Enum<E> & ParentInterface<E>> List<Map<String, Object>> getGenericTypeList() {
List<Map<String, Object>> fuelList = new ArrayList<>();
for(E fuelType : E.values()) {
Map<String, Object> transmission = new HashMap<>();
transmission.put("code", fuelType.getCode());
transmission.put("value", fuelType.getValue());
transmission.put("name", fuelType.getName());
fuelList.add(transmission);
}
return fuelList;
}
This almost works, but the compiler gets upset and says that it doesn't know where to find the E::values method. Annoyingly enough, Java does not permit us to override static methods, so this solution had to get needlessly complicated. Luckily, we already did the complicated part earlier. Instead of trying to use the unknown E::values method, why don't we use the static method we made earlier?
However, in order to use that method, we need to provide a Class<E>. Simple enough, let's also modify our method to take in a Class<E>. And let's also replace that unknown method that just threw an error.
public static <E extends Enum<E> & ParentInterface<E>> List<Map<String, Object>> getGenericTypeList(final Class<E> clazz) {
List<Map<String, Object>> fuelList = new ArrayList<>();
for(E fuelType : ParentInterface.values(clazz)) {
Map<String, Object> transmission = new HashMap<>();
transmission.put("code", fuelType.getCode());
transmission.put("value", fuelType.getValue());
transmission.put("name", fuelType.getName());
fuelList.add(transmission);
}
return fuelList;
}
And then that should be it. You can now delete the unnecessary methods that only work for the individual enums. Here is the complete solution, with some refactoring, renaming, and general clean up.
import java.util.Arrays;
import java.util.List;
import java.util.Map;
public class SOQ_20230108
{
public static void main(String[] args)
{
System.out.println(getParentTypeList(EstimateFuelType.class));
System.out.println(getParentTypeList(EstimateTransmissionType.class));
}
public interface ParentInterface<E extends Enum<E>> // pick a better name
{
String getName();
String getValue();
String getCode();
public static <E extends Enum<E>> List<E> values(final Class<E> clazz)
{
return Arrays.asList(clazz.getEnumConstants());
}
}
public enum EstimateFuelType implements ParentInterface<EstimateFuelType>
{
GASOLINE("가솔린", "A001", "001"),
DIESEL("디젤", "A002", "002"),
LPG_GENERAL("LPG(일반인 구입)", "A003", "003"),
LPG_ALL("LPG", "A004", "004"),
HYBRID("가솔린+전기", "A005", "005"),
ELECTRONIC("전기", "A009", "009"),
ETC("기타", "A999", "999");
final String name;
final String value;
final String code;
EstimateFuelType(String name, String value, String code)
{
this.name = name;
this.value = value;
this.code = code;
}
public String getName()
{
return name;
}
public String getValue()
{
return value;
}
public String getCode()
{
return code;
}
}
public enum EstimateTransmissionType implements ParentInterface<EstimateTransmissionType>
{
AUTO("오토(A/T)", "A001", "001"),
MANUAL("수동(M/T)", "A002", "002"),
ETC("기타", "A999", "999");
final String name;
final String value;
final String code;
EstimateTransmissionType(String name, String value, String code)
{
this.name = name;
this.value = value;
this.code = code;
}
public String getName()
{
return name;
}
public String getValue()
{
return value;
}
public String getCode()
{
return code;
}
}
public static <E extends Enum<E> & ParentInterface<E>> List<Map<String, Object>> getParentTypeList(Class<E> clazz) {
final List<Map<String, Object>> typeList = new ArrayList<>();
for(final E type : ParentInterface.values(clazz)) {
final Map<String, Object> typeMap = new HashMap<>();
typeMap.put("code", type.getCode());
typeMap.put("value", type.getValue());
typeMap.put("name", type.getName());
typeList.add(typeMap);
}
return typeList;
}
}
This complete example has a main method, so you can run it yourself and see that it works.
Finally, if you decide to make this method work for other enums that you add into the future, it is very easy to do. Simply ensure that each enum you add implements your interface, and the parameterized type for that interface should be the enum name itself. If that doesn't make sense, just follow the same format as the other enums and it should work out fine.

Trying to write a generic enum util class in groovy

Problem
We have multiple enum types that have some public static EnumType valueOfText(String text), for the purpose of mapping the contents of a data file cell to enum.
I'm trying to write a generic enum util that takes a comma-separated string and return multiple enum values. For example, we have the following enum:
public enum Frequency {
SEMI_ANNUAL("S"), MONTHLY("M"), QUARTERLY("Q"), ANNUAL("A")
public final String textValue;
public Frequency(String textValue) {
this.textValue = textValue;
}
public static Frequency valueOfText(String textValue) {
for (Frequency frequency : values()) {
if (frequency.textValue.equals(textValue))
return frequency;
}
return null;
}
}
and string "A,S" which we want to convert to [Frequency.ANNUAL, Frequency.SEMI_ANNUAL].
Attempted solution
I create some EnumUtils like so:
import java.util.stream.Collectors
public final class EnumUtils {
public static final String LIST_SEPARATOR = ",";
public static <E extends Enum<E>> List<E> CreateFromText(String text) {
List<String> textList = text.split(this.LIST_SEPARATOR)
return textList.stream()
.map { txt ->
E.valueOfText(txt)
}
.collect(Collectors.toList())
}
}
What happen after said solution
We go to use it, like this:
EnumUtils.CreateFromText<Frequency>(row[3])
and the IDE compain, immediately, about the <>.
How can we specify enum type in this?
In Groovy you can do it if you pass the actual Class instead of just using a type parameter.
enum Frequency {
SEMI_ANNUAL("S"), MONTHLY("M"), QUARTERLY("Q"), ANNUAL("A")
final String textValue;
Frequency(String textValue) {
this.textValue = textValue;
}
static Frequency valueOfText(String textValue) {
return values().find { it.textValue == textValue }
}
}
final class EnumUtils {
static <E extends Enum<E>> List<E> createFromText(Class<E> clazz, String text) {
return text.split(",").collect { clazz.valueOfText(it) }
}
}
EnumUtils.createFromText(Frequency, "S,M")
The same idea won't work in Java, since clazz won't have valueOfText at compile time.
Perhaps the Util class doesn't save you much typing, though:
"S,M".split(",").collect(Frequency.&valueOfText)

Write a single generics method to cover multiple methods for String to Enum value conversion

I created two Java enums,
public enum TypeEnum {
TYPE_A, TYPE_B
}
and
public enum FormatEnum{
FORMAT_X, FORMAT_Y
}
Next, I wrote two functions to convert an incoming String to an enum value:
private TypeEnum convertType(String test) {
return TypeEnum.valueOf(test);
}
private FormatEnum convertFormat(String test) {
return FormatEnum.valueOf(test);
}
Next, I wanted to unify these two conversion methods under a single method with generics. I tried this in two ways:
private <T extends Enum> Enum convertToEnumValue(T localEnum, String value) {
return T.valueOf(localEnum.getClass(), value);
}
and
private static <T extends Enum> T convertToEnumValue(Class<T> enumType, String value) {
return (T) T.valueOf(enumType, value);
}
I couldn't write a call to these methods that would compile.
Is there a way to correct them to make them work?
There is no need to declare your own method, as JDK java.lang.Enum already declares one:
FormatEnum y =Enum.valueOf(FormatEnum.class, "FORMAT_Y");
TypeEnum a = Enum.valueOf(TypeEnum.class, "TYPE_A");
This works because Enum is the base class of all enum types and so when you call TypeEnum.valueOf(s); you are calling Enum.valueOf(s)
…Is there a way to correct them to make them work?…
I got your examples to work with these very small corrections…:
class DeduperAnswer {
private <T extends Enum> T convertToEnumValue(T localEnum, String value) {
return ( T ) T.valueOf(localEnum.getClass(), value);
}
private static <T extends Enum> T convertToEnumValue(Class<T> enumType, String value) {
return ( T ) T.valueOf(enumType, value);
}
static public void main(String ...args){
DeduperAnswer da = new DeduperAnswer();
TypeEnum typB = da.convertToEnumValue(TypeEnum.TYPE_B, "TYPE_B");
FormatEnum fmtX = convertToEnumValue(FormatEnum.FORMAT_X.getClass(), "FORMAT_X");
}
}
Of course, there's more than one way to skin a cat — as the saying goes. But seeing as your solution works for you, you're good to go.
I suspect you are looking for the following method:
public static <E extends Enum<E>> E toMember(Class<E> clazz, String name) {
//TODO input validations;
for (E member : clazz.getEnumConstants()) {
if (member.name().equals(name)) {
return member;
}
}
return null; //Or throw element not found exception
}
//More elegant form of the previous one
public static <E extends Enum<E>> E toMember(Class<E> clazz, String name, E defaultMember) {
//TODO input validations;
for (E member : clazz.getEnumConstants()) {
if (member.name().equals(name)) {
return member;
}
}
return defaultMember;
}
Note the generic E extends Enum<E>

Why this converter needs casting?

I need to implement an enum to enum converter in java: Enum_2 > Enum_1 and I'd like to do it in generic way.
So I defined an interface:
interface LabelAware<T extends Enum> {
String getLabel();
T getObject();
}
and Enum_1:
enum Enum_1 {
A, B;
String getValue() {
return "whatever";
}
}
and Enum_2 which implements LabelAware and needs to be converted to Enum_1:
enum Enum_2 implements LabelAware<Enum_1> {
C("c", Enum_1.A), D("d", Enum_1.B);
private final String label;
private final Enum_1 object;
Enum_2(String label, Enum_1 object) {
this.label = label;
this.object = object;
}
public String getLabel() {
return label;
}
public Enum_1 getObject() {
return object;
}
}
Finally, here's a generic converter (List.ofAll() comes from javaslang):
class Converter<S extends LabelAware, D extends Enum> {
private S[] values;
Converter(S[] values) {
this.values = values;
}
D map(String label) {
return (D) List.of(values)
.find(v -> v.getLabel().equals(label))
.map(LabelAware::getObject)
.getOrElseThrow(() -> new RuntimeException(""));
}
}
And a main method:
public class Main {
public static void main(String[] args) {
System.out.println(new Converter<Enum_2, Enum_1>(Enum_2.values()).map("c").getValue());
}
}
It all compiles and runs well, however I've no idea why I need to cast the result of Converter.map method to D, since I've declared D to extend Enum. Can it be done in a generic way without any warnings?
As a general rule, all warnings related to generics should be handled to have a safer code and avoid a warning chain (the visible warning is caused by a very far warning of the dependency chain).
But in your case, you have not a warning chain problem since externally, LabelAware is safe. LabelAware has only a internal warning (in its implementation) as Enum in extends Enum is raw-declared.
Here, a single missing generic declaration explains why the cast in Converter.map() method is not safe : Converter class declaration doesn't specify the generic for LabelAware.
You declare Converter class as :
class Converter<S extends LabelAware, D extends Enum> {
with its value field of type S:
private S[] values;
and its map() method as :
D map(String label) {
return (D) List.of(values)
.find(v -> v.getLabel().equals(label))
.map(LabelAware::getObject)
.getOrElseThrow(() -> new RuntimeException(""));
}
In map(), here .find(v -> v.getLabel().equals(label)), your retrieve so a S instance and you declared that S extends LabelAware.
Therefore finally, your retrieve an instance of LabelAware or extending it.
And LabelAware is typed with Enum generic :
interface LabelAware<T extends Enum> {
String getLabel();
T getObject();
}
So, in map() method when .map(LabelAware::getObject) is called, you retrieve a Enum type .
And an Enum type is not necessarily a D type, while the reverse is true.
Therefore, if you want to avoid the cast (and the related warning) in map(), you should specify that the generic type returned by getObject() is an instance of D by typing LabelAware with D generic :
class Converter<S extends LabelAware<D>, D extends Enum> {
You have been using raw types at several places (not only the one that yshavit pointed out in the comment). Particularly, the
class Converter<S extends LabelAware, D extends Enum>
has to be
class Converter<S extends LabelAware<D>, D extends Enum<D>>
The following should compile without warnings:
import javaslang.collection.List;
interface LabelAware<T extends Enum<?>>
{
String getLabel();
T getObject();
}
enum Enum_1
{
A, B;
String getValue()
{
return "whatever";
}
}
enum Enum_2 implements LabelAware<Enum_1>
{
C("c", Enum_1.A), D("d", Enum_1.B);
private final String label;
private final Enum_1 object;
Enum_2(String label, Enum_1 object)
{
this.label = label;
this.object = object;
}
public String getLabel()
{
return label;
}
public Enum_1 getObject()
{
return object;
}
}
class Converter<S extends LabelAware<D>, D extends Enum<D>>
{
private S[] values;
Converter(S[] values)
{
this.values = values;
}
D map(String label)
{
return List.of(values)
.find(v -> v.getLabel().equals(label))
.map(LabelAware::getObject)
.getOrElseThrow(() -> new RuntimeException(""));
}
}
(EDIT: This only tells you how to fix the problem, pragmatically. See the answer by davidxxx for details about what went wrong there, and don't forget to leave a +1 there :-))

How to resolve an incompatible upper bounds error for method that returns generic Enum

I gave an interface to define behavior for enums with reverse lookup capability:
public interface Enumerable {
public String getName();
public <E extends Enum<E>> E getByName(String name);
}
Here is an enum that implements the interface:
public enum SubMenu implements Enumerable {
SIMPLE_MENU("An Option");
private final String name;
public static final Map<String,SubMenu> lookup = new HashMap<>();
static {
for (SubMenu subMenu : EnumSet.allOf(SubMenu.class)) {
lookup.put(subMenu.getName(), subMenu);
}
}
private SubMenu(final String name) {
this.name = name;
}
public final String getName() { return name; }
public SubMenu getByName(String name) {
return lookup.get(name);
}
}
When I try to assign the return value of getByName(String name) to a variable of a specific enum type, I get this error: "incompatible types: inference variable E has incompatible upper bounds java.lang.Enum,SubMenu". How do I resolve this error?
public final List<Enumerable> getSubMenuOptions(final Enumerable subMenu) {
//Here is where I get the error
SubMenu sm = subMenu.getByName(subMenu.getName());
.....
}
You should enhance the Enumerable interface signature with an additional type argument
public interface Enumerable<E extends Enum<E>> {
public String getName();
public E getByName(String name);
}
and adjust the rest of the code accordingly:
public enum SubMenu implements Enumerable<SubMenu> {
MENU_OPTION_1("An Option"),
MENU_OPTION_2("Another Option";
private final String localizedName;
private SubMenu(final String localizedName){
this.localizedName = localizedName;
}
#Override
public String getName() {
return this.localizedName;
}
#Override
public SubMenu getByName(final String pName) {
for(SubMenu menu : values()){
if(menu.name().equals(pName)
|| menu.localizedName.equals(pName)){
return menu;
}
}
return null;
}
}
public class ClientClass{
/**
* This method can work with SubMenu, if you explicitly exchange the generic E with SubMenu
*/
public <E extends Enum<E>> E getSubMenuOptions(final Enumerable<E> submenu){
E sm = submenu.getByName(submenu.getName());
return sm;
}
}
The parameter you pass is of type Enumerable.
The type itself is not generic, it just has a generic method.
The generic method defines that its return type is some (unknown) Enum type.
So when you call subMenu.getByName(submenu.getName()), the type of the result is basically "An unknown Enum".
Now you try to assign this to a specific variable of type SubMenu. Since "An unknown Enum" may be any Enum in the world, you can't assign it without type casting to a variable of the specific type SubMenu. The true type returned may, indeed, be SubMenu, but since Enumerable is not generic, the compiler has no way of knowing that.

Categories

Resources