9

注釈プロセッサを使用して、注釈付きクラスのメソッドの戻り値の型に応じてソース コードを生成するツールを作成しています。A戻り値の型は常に、型変数を定義するインターフェイスのサブタイプ (インターフェイスまたはクラス)ですT

interface A<T>{T m();};

m()メソッドの戻り値型 variableの型パラメーターを見つけたいと思いますT

戻り値の型は、注釈プロセッサによってインスタンスとして表されjavax.lang.model.type.TypeMirrorます。A<T>最も単純なケースは、直接戻ることです。

@SomeAnnotation
class SomeClass{
    A<T> x();
}

検出するプロセッサ コードTは非常に単純です。(コードをシンプルにするために、ここではビジター API を使用する代わりにキャストします。)

DeclaredType type = (DeclaredType) typeMirror;
TypeMirror t = type.getTypeArguments().get(0);

TypeMirror戻り型の は aでjavax.lang.model.type.DeclaredTypeありT、最初の型引数です。結果tjavax.lang.model.type.TypeVariableforTです。同じことが具体的な戻り値の型A<B>( Bis some type: interface B{}) に対しても機能します。の結果tは をDeclaredType表していBます。

他の結果タイプでは事態が複雑になり始めます。

interface Subtype<T> extends A<T>{}
interface Concrete extends A<B>{};
interface Multiple<B,T> extends A<T>{}
interface Bounds<T extends B> extends A<T>{}
interface Hierarchy extends Concrete{}
Subtype<B>          -> DeclaredType B
Subtype<T>          -> TypeVariable T
Concrete            -> DeclaredType B
Multiple<B,T>       -> TypeVariable T or DeclaredType B depeding on Multiple
Multiple<B,B>       -> TypeVariable B
<T extends B> A<T>  -> TypeVariable T with super class bound B
Bound<B>            -> DeclaredType B
Bound<C>            -> DeclaredType C (subtype of B)
Hierarchy           -> TypeVariable T

TJava型システム全体をミラーリングせずに正しい型パラメータを見つける方法はありますか?

4

3 に答える 3

6

http://docs.oracle.com/javase/6/docs/api/javax/lang/model/util/Types.html#asMemberOf%28javax.lang.model.type.DeclaredType,%20javax.langをご覧ください。.model.element.Element%29

私はそれを使用してこの問題を解決し、このプル リクエストで WsDoc プロジェクトにソリューションを提供しました: https://github.com/versly/wsdoc/pull/7

私はこのようなことをしました:

      Type.MethodType methodType = (Type.MethodType) processingEnv.getTypeUtils().asMemberOf(declaredTypeThatExtendsSomeGenericParent, methodToGetReturnTypeForAsExecutableElement);
      TypeMirror type = methodType.getReturnType();
于 2013-01-15T18:58:02.633 に答える
3
 public AnnotationProcessor getProcessorFor(
            Set<AnnotationTypeDeclaration> atds,
            AnnotationProcessorEnvironment env) {
        return new SomeAnnotationProcessor(env);
    }

    private static class SomeAnnotationProcessor implements AnnotationProcessor {
        private final AnnotationProcessorEnvironment env;

        SomeAnnotationProcessor(AnnotationProcessorEnvironment env) {
            this.env = env;
        }

        public void process() {
            for (TypeDeclaration typeDecl : env.getSpecifiedTypeDeclarations()) {
                System.out.println("in class: " + typeDecl);
                typeDecl.accept(getDeclarationScanner(
                        new SomeClassVisitor(), NO_OP));
            }
        }

        private static class SomeClassVisitor extends SimpleDeclarationVisitor {
            @Override
            public void visitMethodDeclaration(
                    MethodDeclaration methodDeclaration) {
                System.out.println("visiting method: "+methodDeclaration + " -> "+methodDeclaration.getReturnType());
                methodDeclaration.getReturnType().accept(new SomeTypeVisitor());
            }
        }
    }

    private static class SomeTypeVisitor implements TypeVisitor {

        public void visitClassType(ClassType classType) {           
            System.out.println("classType: " + classType + " -> "+classType.getClass());                
        }

        @Override
        public void visitInterfaceType(InterfaceType interfaceType) {
            Types types = annotationProcessorEnvironment.getTypeUtils();
            TypeDeclaration typeDeclaration = annotationProcessorEnvironment
                    .getTypeDeclaration("A");           
            Collection<InterfaceType> superinterfaces = interfaceType
                    .getSuperinterfaces();                      
            System.out.println("interfaceType: " + interfaceType + " -> "
                    + superinterfaces);
            DeclaredType typeOfA = types.getDeclaredType(typeDeclaration);
            boolean isSubTypeOfA = types.isSubtype(interfaceType, typeOfA);         
            if (isSubTypeOfA) {
                findTypeVariable(types, superinterfaces, typeOfA);
            }
            Iterator<TypeMirror> iterator = interfaceType
                    .getActualTypeArguments().iterator();
            while (iterator.hasNext()) {
                TypeMirror next = iterator.next();
                next.accept(new SomeTypeVisitor());
            }
        }

        public void visitTypeVariable(TypeVariable typeVariable) {          
            System.out.println("typeVariable: "
                    + typeVariable.getDeclaration() + " -> "+typeVariable.getClass());              
        }

        private void findTypeVariable(Types types,
                Collection<InterfaceType> superinterfaces, DeclaredType typeOfA) {
            for (InterfaceType superInterface : superinterfaces) {
                TypeMirror erasure = types.getErasure(superInterface);
                if (erasure.equals(typeOfA)) {
                    System.out.println("true, "+superInterface.getActualTypeArguments());
                } else {
                    System.out.println("false: " + typeOfA + " =!= "
                            + erasure);
                    findTypeVariable(types, superInterface.getSuperinterfaces(), typeOfA);
                }
            }
        }


    }
于 2009-09-09T13:36:41.487 に答える