Java: reflection for getting Enum

This is similar, but not quite the same as Java: instantiating using reflection

I have a Map<Enum<?>, FooHandler> , which I want to use to display Enum (I don't care what type or even if they are of the same type, as long as they are enumeration constants) to my FooHandler class.

I would like to fill out this card using a text file that I read. I can make it work, but I have two warnings that I would like to get around:

 static private <E extends Enum<E>> E getEnum(String enumFullName) { // see https://stackoverflow.com/questions/4545937/ String[] x = enumFullName.split("\\.(?=[^\\.]+$)"); if (x.length == 2) { String enumClassName = x[0]; String enumName = x[1]; try { Class<E> cl = (Class<E>)Class.forName(enumClassName); // #1 return Enum.valueOf(cl, enumName); } catch (ClassNotFoundException e) { e.printStackTrace(); } } return null; } public void someMethod(String enumName, String fooHandlerName) { FooHandler fooHandler = getFooHandler(fooHandlerName); Enum e = getEnum(enumName); // #2 map.put(e, fooHandler); } 

Warning # 1: Unchecking Warning # 2: Enum is a raw type.

I get # 1 and can just put a warning, I suppose, but it seems like I can't beat warning # 2; I tried Enum<?> And it just gives me an error about a generic type binding mismatch.


Alternative implementations that are worse: Until my return value <E extends Enum<E>> I tried to return Enum, and this did not work; I received these warnings / errors:

 static private Enum<?> getEnum(String enumFullName) { ... Class<?> cl = (Class<?>)Class.forName(enumClassName); // 1 return Enum.valueOf(cl, enumName); // 2 } 
  • warnings:

      - Type safety: Unchecked cast from Class<capture#3-of ?> to Class<Enum> - Enum is a raw type. References to generic type Enum<E> should be parameterized - Enum is a raw type. References to generic type Enum<E> should be parameterized - Unnecessary cast from Class<capture#3-of ?> to Class<?> 
  • errors:

     - Type mismatch: cannot convert from capture#5-of ? to Enum<?> - Type safety: Unchecked invocation valueOf(Class<Enum>, String) of the generic method valueOf(Class<T>, String) of type Enum - Bound mismatch: The generic method valueOf(Class<T>, String) of type Enum<E> is not applicable for the arguments (Class<capture#5-of ?>, String). The inferred type capture#5-of ? is not a valid substitute for the bounded parameter <T extends Enum<T>> 

and this:

 static private Enum<?> getEnum(String enumFullName) { ... Class<Enum<?>> cl = (Class<Enum<?>>)Class.forName(enumClassName); // 1 return Enum.valueOf(cl, enumName); // 2 
  • warning: Type safety: Unchecked cast from Class<capture#3-of ?> to Class<Enum<?>>
  • error: Bound mismatch: The generic method valueOf(Class<T>, String) of type Enum<E> is not applicable for the arguments (Class<Enum<?>>, String). The inferred type Enum<?> is not a valid substitute for the bounded parameter <T extends Enum<T>> Bound mismatch: The generic method valueOf(Class<T>, String) of type Enum<E> is not applicable for the arguments (Class<Enum<?>>, String). The inferred type Enum<?> is not a valid substitute for the bounded parameter <T extends Enum<T>>
+8
java reflection enums
source share
2 answers

There is no solution for # 1 except SuppressWarnings("unchecked") .

There is a declaration issue for # 2:

 static private <E extends Enum<E>> E getEnum(String enumFullName) 

You can return E , but the compiler cannot determine E There are no arguments like E or Class<E> or anything else that would allow this. You can write it, but there will be an uncontrolled throw somewhere, and when you call it, you can get a ClassCastException . So do not do this.

Just change it to

 static private Enum<?> getEnum(String enumFullName) 

as it will work more equitably. You will receive a warning on every call site and this is correct, since there is something to warn.

+6
source share

Signature

 static private <E extends Enum<E>> getEnum(String enumFullName) 

it doesn't help you here.

<E extends Enum<E>> allows the caller to assign the result of getEnum any type of enum they want, without casting:

 SomeEnum e = getEnum("com.foo.SomeOtherEnum.SOMETHING"); // ClassCastException! 

However, this makes no sense ... if the caller knew which particular type of enum method returned, they could do something more sensible, like SomeEnum.valueOf("SOMETHING") .

The only thing that makes sense here is getEnum just return Enum<?> , Which looks like what you really want to do anyway:

 static private Enum<?> getEnum(String enumFullName) { String[] x = enumFullName.split("\\.(?=[^\\.]+$)"); if(x.length == 2) { String enumClassName = x[0]; String enumName = x[1]; try { @SuppressWarnings("unchecked") Class<Enum> cl = (Class<Enum>) Class.forName(enumClassName); return Enum.valueOf(cl, enumName); } catch(ClassNotFoundException e) { e.printStackTrace(); } } return null; } 

The above compilations without warnings and proper operation. The warning is discarded in Class<Enum> because we know that it is unsafe and that Enum.valueOf explode if the class with the given name is not the enum class and what we want to do.

+5
source share

Source: https://habr.com/ru/post/651314/


All Articles