how to cast to CRTP in java?

孤街浪徒 提交于 2019-12-22 22:50:10

问题


I have a pretty simple case where I do some basic generic assignment:

final Detail detail = field.getAnnotation(Detail.class);
final String example = detail.example();
final Class<?> type = field.getType();
if (List.class.isAssignableFrom(type))
                    ...
else if (Enum.class.isAssignableFrom(type))
    setValue(contract, field, Enum.valueOf(type, example));
else if (...)
.....

but the Enum.valueOf() is a bit difficult to call, in my case, the error is:

valueOf(java.lang.Class,java.lang.String) in java.lang.Enum cannot be applied to (java.lang.Class,java.lang.String)

This makes perfectly sense since type is Class<Object>. But since Enum is CRTP, I can't find a good way to cast type to make the compiler happy. Is using the raw type Enum.valueOf((Class)type, example)) the only answer? It gives me 2 warnings instead of only one.


回答1:


The following line will do it with only one warning:

...
setValue( contract, field, Enum.valueOf( type.asSubclass( Enum.class ), example ) );
...



回答2:


You can write a helper method to capture a "T" type that satisfies Enum's requirement:

private <T extends Enum<T>> T helper(Class<?> type, String example) {
    return Enum.valueOf((Class<T>)type, example);
}

this should only have one warning

and then you can use it like

else if (Enum.class.isAssignableFrom(type))
    setValue(contract, field, helper(type, example));

Edit: okay, then how about:

private <T extends Enum<T>> Object helper(Class<?> type, String example) {
    return Enum.valueOf((Class<T>)type, example);
}



回答3:


I don't think it's possible to remove the compiler warnings

The best case scenario is reducing all the errors into one like @tangens does.

Found two forum threads that show unsuccessful answers and explains the why a bit more.

  • http://forums.sun.com/thread.jspa?threadID=5215278
  • http://forums.sun.com/thread.jspa?threadID=694354

So I put together a full example to demonstrate the issue as I see it.

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Field;
import java.util.List;

public class Test {
  @Retention(RetentionPolicy.RUNTIME)
  @Target(ElementType.FIELD)
  public @interface Detail {
    String example();
  }

  public enum ExampleEnum {
    FOO_BAR, HELLO_WORLD
  }

  @Detail(example = "FOO_BAR")
  public ExampleEnum test;

  public static void main(String[] args) throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException {
    populate(new Test());
  }

  public static void populate(Object o) throws IllegalArgumentException, IllegalAccessException, SecurityException, NoSuchFieldException {
    final Field field = o.getClass().getField("test");
    final Detail detail = field.getAnnotation(Detail.class);
    System.out.println("Annotation = " + detail);
    final String example = detail.example();
    final Class<?> type = field.getType();
    System.out.println("Field Class = " + type.getName());
    if (List.class.isAssignableFrom(type)) {
    } else if (Enum.class.isAssignableFrom(type)) {
      Class<? extends Enum> enumType = type.asSubclass(Enum.class); // Enum is a raw type. References to generic type Enum<E> should be parameterized
      Enum val = Enum.valueOf(enumType, example); // 1) Enum is a raw type. References to generic type Enum<E> should be parameterized
                                                  // 2) Type safety: Unchecked invocation valueOf(Class<capture#7-of ? extends Enum>, String) of the generic
                                                  //    method valueOf(Class<T>, String) of type Enum
      field.set(o, val);
    }
  }
}


来源:https://stackoverflow.com/questions/1458779/how-to-cast-to-crtp-in-java

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!