检查方法参数的泛型类型

时间:2014-10-05 17:47:54

标签: java generics reflection

我不知道这是否可以用Java完成。我无法找到解决方案。

我想检查一个类中的所有方法,并找出该方法的参数如何与通用信息一样。例如,如果您有一个接口和一个如下所示的实现者:

// Services are the objects i will examine

public interface Service<T extends DetailsModel> {
   public Response findObject(RequestEvent<T> event);
}

public interface SomeObjectService extends Service<SomeObject> {
   Response findObject(RequestEvent<SomeObject> event);
}

public class SomeObjectServiceImpl extends SomeObjectService  {
   public Response findObject(RequestEvent<SomeObject> event) {...}
}

// Events are the parameters of the services

public interface Event<T extends DetailsModel> {
   Callback getCallback()
}

public abstract class AbstractEvent<T> implements Event<T> {

  public Callback getCallback() {
     return null;
  }
}

public class RequestEvent<T> extends AbstractEvent<T> {
    Handle<T> t;

    public Handle<T> getHandle() {...}
}

在查看SomeObjectServiceImpl时,我尝试过所有类型的东西来获取RequestEvent的实际值。例如

public <D extends DetailsModel> void configure(Service<D> service) {
   Method[] allDeclaredMethods = service.getClass().getDeclaredMethods();

   for (Method declaredMethod : allDeclaredMethods) {
     try {
        Type[] parameterTypes = declaredMethod.getGenericParameterTypes();
        if (parameterTypes.length == 1) {
           Type parameterType = parameterTypes[0];
           if (Event.class.isAssignableFrom((Class<?>) parameterType)) {
              ParameterizedType type = ((ParameterizedType) ((Class) parameterType).getGenericSuperclass());
              Type genericType = type.getActualTypeArguments()[0];
              if (genericType != null && genericType instanceof Class) {
                 EventDescriber eventDescriber = new EventDescriber(
                       (Class<? extends Event>) parameterType,
                       (Class) genericType);
              }
           }
        } 
     } catch (Exception e) {
        logger.warn("Could not map " + declaredMethod, e);
     }
  }

然后我想检查SomeObjectServiceImpl中的方法的结果如下:

ServiceImpl:
  findObject: 
     RequestEvent
        SomeObject (I cant find this. Instead I find a TypeVariableImpl.)

你能用java反射吗?

2 个答案:

答案 0 :(得分:1)

当然,这是可能的。使用Method检索[通用参数类型] [1]。

Method method = ServiceImpl.class.getMethod("doSomething",
            DoSomethingEvent.class);
ParameterizedType type = (ParameterizedType)method.getGenericParameterTypes()[0];

然后访问[原始类型] [2]和[实际类型参数] [3]。

type.getRawType();
type.getActualTypeArguments()[0]; // first type argument

这是一个有效的例子

public class Test {
    public static void main(String[] args) throws Exception {
        configure(new ServiceImpl());
    }

    public static <T> void configure(Service<T> service) {
        Method[] allDeclaredMethods = service.getClass().getDeclaredMethods();

        for (Method declaredMethod : allDeclaredMethods) {
            try {
                Class<?>[] parameterTypes = declaredMethod.getParameterTypes();
                if (parameterTypes.length == 1) {
                    Class<?> parameterType = parameterTypes[0];
                    if (Event.class.isAssignableFrom(parameterType)) {
                        ParameterizedType type = ((ParameterizedType) declaredMethod
                                .getGenericParameterTypes()[0]);
                        Type typeArgument = type.getActualTypeArguments()[0];
                        System.out.println("Parameter type: " + type.getRawType() + ", Generic type argument: " + typeArgument);
                    }
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }
}

interface Response {
}

interface Service<T> {
    public Response findObject(RequestEvent<T> event);
}

class ServiceImpl implements Service<SomeObject> {
    public Response findObject(RequestEvent<SomeObject> event) {
        return null;
    }

    public Response doSomething(DoSomethingEvent<SomethingAction> event) {
        return null;
    }
}

interface Event<T> {
}

interface SomethingAction {
}

class SomeObject {
}

class DoSomethingEvent<T> extends RequestEvent<T> {
}

interface Handle<T> {
}

class RequestEvent<T> implements Event<T> {
    Handle<T> t;

    public Handle<T> getHandle() {
        return null;
    }
}

打印

Parameter type: class com.example.RequestEvent, Generic type argument: class com.example.SomeObject
Parameter type: class com.example.DoSomethingEvent, Generic type argument: interface com.example.SomethingAction

答案 1 :(得分:0)

我刚做了同样的事情。限于Iterable,但反射代码非常相似:

/**
 * Assuming the given method returns or takes an Iterable<T>, this determines the type T.
 * T may or may not extend WindupVertexFrame.
 */
private static Class typeOfIterable(Method method, boolean setter)
{
    Type type;
    if (setter) {
        Type[] types = method.getGenericParameterTypes();
        // The first parameter to the method expected to be Iterable<...> .
        if (types.length == 0)
            throw new IllegalArgumentException("Given method has 0 params: " + method);
        type = types[0];
    }
    else {
        type = method.getGenericReturnType();
    }

    // Now get the parametrized type of the generic.
    if (!(type instanceof ParameterizedType))
        throw new IllegalArgumentException("Given method's 1st param type is not parametrized generic: " + method);
    ParameterizedType pType = (ParameterizedType) type;
    final Type[] actualArgs = pType.getActualTypeArguments();
    if (actualArgs.length == 0)
        throw new IllegalArgumentException("Given method's 1st param type is not parametrized generic: " + method);

    Type t = actualArgs[0];
    if (t instanceof Class)
        return (Class<?>) t;

    if (t instanceof TypeVariable){
        TypeVariable tv =  (TypeVariable) actualArgs[0];
        AnnotatedType[] annotatedBounds = tv.getAnnotatedBounds();///
        GenericDeclaration genericDeclaration = tv.getGenericDeclaration();///
        return (Class) tv.getAnnotatedBounds()[0].getType();
    }

    throw new IllegalArgumentException("Unknown kind of type: " + t.getTypeName());
}