2017-12-29 11 views
0

私はカスタム注釈プロセッサを書いています。ジェネリック型ではなくクラス型を処理することはできますが、ジェネリック型では実際の型を取得できません。typeElementから実際の型を取得する方法は?

MyBaseインタフェース

interface MyBase<T, S> { 
    void method1(S, T); 
} 

例Class1の

public class KpA{ 
... 
} 

例クラス2

public class KpB{ 
... 
} 

ターゲット注釈クラス

@MyAnnotation 
interface MyHandler extends MyBase<KpA, KpB>{ 

} 

処理コードスニペット

TypeElement[] getActualTypes(ProcessingEnvironment pEnv, TypeElement element){ 
     List<TypeElement> myBaseElement = element.getInterfaces().stream().map(v-> (TypeElement) pEnv.getTypeUtils().asElement(v)).collect(Collectors.toList()); 
     myBaseElement.get(0).getTypeParameters().stream().forEach(System.out::println); 
     return null; 
    } 

私はS and Tがどのように私はKpA and KpBを得ることができるよう、私は出力を得るgetTypeParametersをSysout

この問題を解決するには、何か助けてください。

答えて

1

タイプシステムに対処する場合は、正確にはが欲しいと理解することが重要です。それらの型パラメータは、基本型のいくつかのフィールド/メソッドで型変数が使用されているので、必要ですか?例えば。あなたのパラメータ化された基本型はCollection<SomeItem>のようなもので、戻り値の型はaddです。またはMyBaseClonableのようなマーカーインターフェイスのいくつかの種類であり、正確にのパラメータですか?

何でも;あなたの状況はあなたの質問に正確に記載されていると仮定しよう:MyBaseはいくつかのインターフェイスです。ここではそれを達成するために柔軟性のない、ダムの方法である:

// instance of javax.lang.model.util.Types 
protected final Types types; 

// instance of javax.lang.model.util.Elements 
protected final Elements el; 

// TypeMirror for java.lang.Object 
protected final TypeMirror theObject = ... 

private static final TYPE_REFINER = new DeclaredTypeRefiner(); 

private class DeclaredTypeRefiner extends TypeKindVisitor6<DeclaredType, TypeMirror> { 
    @Override 
    public DeclaredType visitDeclared(DeclaredType type, TypeMirror desirableParent) { 
    if (types.isSameType(types.erasure(type), desirableParent)) { 
     return type; 
    } 

    return null; 
    } 

    @Override 
    public DeclaredType visitUnknown(TypeMirror typeMirror, TypeMirror typeMirror2) { 
    return defaultAction(typeMirror, typeMirror2); 
    } 

    @Override 
    protected DeclaredType defaultAction(TypeMirror type, TypeMirror desirableParent) { 
    if (types.isSameType(type, theObject)) { 
     return null; 
    } 

    final List<? extends TypeMirror> superTypes = types.directSupertypes(type); 

    for (TypeMirror parent : superTypes) { 
     final DeclaredType discovered = visit(parent, desirableParent); 

     if (discovered != null) { 
     return discovered; 
     } 
    } 

    return null; 
    } 
} 

public TypeMirror getTypeArg(TypeMirror actual, TypeMirror base, int idx) { 
    DeclaredType found = TYPE_REFINER.visit(actual, types.erasure(base)); 

    return found.getTypeArguments().get(idx); 
} 

第二パラメータ(例えばKpB)の種類を取得するには:ここでは

// type mirror of MyHandler goes here 
TypeMirror concrete = ... 

// your base type goes here. Real code should cache it 
TypeMirror base = types.getDeclaredType(el.getTypeElement("com.example.MyBase")); 

// boom 
TypeMirror arg = typeHelper.getTypeArg(concrete, base, 1); 

はここで何が起こっている:

  1. DeclaredType(クラスやインタフェースなど)を探す親の型に反復する
  2. 宣言された型がベースであるかどうかをチェックする私たちがそれを見つけた場合、それは型引数に

を確認することができますので、呼び出し元にそれをインターフェース

  • 戻るトリックはdirectSupertypesへの呼び出しである:それのマニュアルで説明したように、その方法は、自動的にあなたのための型引数を解決しました。

    タイプイレージャ(生のタイプともいう)は、意味のある方法で比較可能であることが予想されるため(これはTypeElementsの比較とほぼ同じです)比較されます。 isSameTypeとジェネリックタイプを比較しようとしないでください。タイプシステムが動作するため、驚くべき結果が得られることが保証されています。


    上記のコードは、常に複数の継承のために正しい結果を提供しない場合があるので注意してください、:MyHandlerTSの本当のアイデンティティについての混乱につながる、複数の親からMyBaseを継承することができます。これらの変数がどこにも使われていないと(純粋なマーカインタフェースについて話しているなど)、それは謎のままです:コンパイラは気にしないので、誰も知らない(手動で計算したくないこれらの変数がいくつかのメソッド/フィールドで使用されている場合は、MyHandlerのメソッド/フィールドを調べて型を取得できるようにする必要があります(これは別の質問に値するやや難しい問題です) 。

  • +0

    入力していただきありがとうございます。しかし、あなたの意見はもっと貴重でした。 –

    関連する問題