2017-07-09 12 views
2

私はタイプがEvent<Something>の単一のパラメータを持つメソッドを持ち、Somethingまたはその生の型を抽出する必要があります。それは正式なメソッドのパラメータ型の引数を取得するにはどうすればよいですか?

void method1(Event<MyEnum1> event) {} 
<E extends Enum<E>> method2(Event<E> event) {} 
<K, V> method3(Event<Map<K, V>> event) {} 

のように見えるかもしれませんし、私はmethod1用関数マッピング

method1 -> MyEnum.class 
method2 -> Enum.class 
method3 -> Map.class 

が欲しい、それが(ParameterizedType) method.getGenericParameterTypes()を使用して簡単です。 method2のために、私はParameterを得ることがType

TypeToken.of(method.getDeclaringClass()) 
    .method(method) 
    .getParameters() 
    .get(0) 

を得るために、グアバ

TypeToken.of(method.getDeclaringClass()) 
    .method(method) 
    .getTypeParameters()[0] 
    .getBounds() 

を使用することができます。私は、Typeを使用してParameterを解決する必要があると思いますが、ここで取り残されています。

私はmethod3について気にしませんが、一般的な方法を知っておくとよいでしょう。私は実際のパラメータのタイプについて気にしない(私は消去を認識している)。

+0

うち上記印刷物それは私が失敗した理由を知るために誰かのために興味深いものがあります。受け入れられた答えが示すように、それは実際には簡単です。私の問題は、 'typeArgument'が' TypeVariableImpl'であり、Eclipseでそれを開き、それが非公開で、どんなインターフェースも実装していないことが分かったことです(これは 'Type'のように不可能ですが、関連クラスは 'sun.reflect.generics.reflectiveObjects.TypeVariableImpl'(sources.jarにはありません)でしたが、私が見ていたものではありませんでした。 – maaartinus

答えて

3

これにはTypeTokenは必要ありません。 java.lang.reflectは必要なものすべてを提供します。

複数のケースを考慮する必要があります。提供されるメソッドの最初のパラメータは、常にタイプEvent(または実際にはパラメータ化されたタイプ)であると仮定します。

Typeの5つのサブタイプを処理する必要があります。あなたの例から、型引数が具体的な型(MyEnum)、型変数(Eが束縛されたEnum)、またはパラメータ化された型(Map<K,V>)かどうかをチェックする必要があります。

さらに、変数variableおよび抽出範囲のように処理できるWildcardTypeがあります。最後に、GenericArrayTypeEvent<T[]>またはEvent<List<String>[]>)という汎用配列型を扱わなければなりません。私はこれらを残しましたが、他のタイプに対しても同じルールを適用しています。

変数型の場合、バインドは他の型の変数であると仮定します。したがって、具体的な境界が見つかるまで繰り返す必要があります。小さなドライバプログラム

public static void main(String[] args) throws Exception { 
    Class<?> clazz = Example.class; 
    for (Method method : clazz.getDeclaredMethods()) { 
     if (!method.getName().startsWith("method")) { 
      continue; 
     } 
     System.out.println("Method '" + method + "' -> " + getRawTypeArgument(method)); 
    } 
} 

// get raw type argument of first parameter 
public static Class<?> getRawTypeArgument(Method method) { 
    Parameter parameter = method.getParameters()[0]; 
    Type type = parameter.getParameterizedType(); 
    /// assume it's parameterized 
    ParameterizedType parameterizedType = (ParameterizedType) type; 
    // assume there's one type argument 
    Type typeArgument = parameterizedType.getActualTypeArguments()[0]; 
    if (typeArgument instanceof TypeVariable<?>) { 
     TypeVariable<?> typeVariableArgument = (TypeVariable<?>) typeArgument; 
     return recursivelyExtractBound(typeVariableArgument); 
    } else if (typeArgument instanceof Class<?>) { 
     return (Class<?>) typeArgument; 
    } else if (typeArgument instanceof ParameterizedType) { 
     ParameterizedType parameterizedTypeArgument = (ParameterizedType) typeArgument; 
     return (Class<?>) parameterizedTypeArgument.getRawType(); 
    } 
    throw new AssertionError("Consider wildcard and generic type"); 
} 

private static Class<?> recursivelyExtractBound(TypeVariable<?> typeVariable) { 
    // assume first 
    Type bound = typeVariable.getBounds()[0]; 
    if (bound instanceof Class<?>) { 
     return (Class<?>) bound; 
    } else if (bound instanceof TypeVariable<?>) { 
     TypeVariable<?> nested = (TypeVariable<?>) bound; 
     return recursivelyExtractBound(nested); 
    } else if (bound instanceof ParameterizedType) { 
     ParameterizedType parameterizedTypeArgument = (ParameterizedType) bound; 
     return (Class<?>) parameterizedTypeArgument.getRawType(); 
    } 
    throw new AssertionError("Are there others?"); 
} 

Method 'java.lang.Object com.example.Example.method3(com.example.root.Event)' -> interface java.util.Map 
Method 'java.lang.Object com.example.Example.method2(com.example.root.Event)' -> class java.lang.Enum 
Method 'void com.example.Example.method1(com.example.Event)' -> class com.example.MyEnum1 
+1

これは本当に素晴らしいです!しかし、私は 'IllegalStateException'を' AssertionError'に変更するだけです。あなたが主張しているプログラマーとして、あなたがカバーできるケースは他にないからです。また、['IllegalStateException'](http://docs.oracle.com)も参照してください。com/javase/8/docs/api/java/lang/IllegalStateException.html)は主に呼び出されるオブジェクトの状態を参照しており、ここで呼び出されるメソッドは静的です。静的と状態は通常一緒にうまくいっていない;) –

+0

@OlivierGrégoireうん。 –

+0

@OlivierGrégoire私はこの変更についてはわかりません。存在していれば 'AssertionRuntimeException'が好きです。 'AssertionError'はキャッチをスローして問題を引き起こす可能性があります。 Guavaの人もそれを使用しています。 – maaartinus

関連する問題