2014-10-05 146 views
1

我不知道這是否可以在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時,我已經嘗試了所有樣的東西得到實際的T出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反射做到這一點?

回答

1

當然,這是可能的。使用Method來檢索[通用參數類型] [1]。

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

然後訪問[raw type] [2]和[actual type arguments] [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 
+0

@AnAmuser您檢索哪個'方法? – 2014-10-05 18:13:12

+0

這也行不通。 type.getActualTypeArguments()[0]返回一個TypeVariableImpl(name =「T」,bounds = null,...)。這發生在兩種方法上。如果這有所幫助,我會使用新的ServiceImpl()。getClass()。getMethod(..)。 – AnAmuser 2014-10-05 18:28:52

+0

@AnAmuser什麼是'ModelServiceImpl'?我要解決你的問題。 – 2014-10-05 18:30:51

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()); 
}