Find type parameter of method return type in Java 6 annotation processor

大城市里の小女人 提交于 2019-11-29 04:09:14

Have a look at 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

I used it to solve this problem and contributed the solution to the WsDoc project in this pull request: https://github.com/versly/wsdoc/pull/7

I did something like this:

      Type.MethodType methodType = (Type.MethodType) processingEnv.getTypeUtils().asMemberOf(declaredTypeThatExtendsSomeGenericParent, methodToGetReturnTypeForAsExecutableElement);
      TypeMirror type = methodType.getReturnType();
 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);
                }
            }
        }


    }

This seems to be a common question so, for those arriving from Google: there is hope.

The Dagger DI project is licensed under the Apache 2.0 License and contains some utility methods for working with types in an annotation processor.

In particular, the Util class can be viewed in full on GitHub (Util.java) and defines a method public static String typeToString(TypeMirror type). It uses a TypeVisitor and some recursive calls to build up a string representation of a type. Here is a snippet for reference:

public static void typeToString(final TypeMirror type, final StringBuilder result, final char innerClassSeparator)
{
    type.accept(new SimpleTypeVisitor6<Void, Void>()
    {
        @Override
        public Void visitDeclared(DeclaredType declaredType, Void v)
        {
            TypeElement typeElement = (TypeElement) declaredType.asElement();

            rawTypeToString(result, typeElement, innerClassSeparator);

            List<? extends TypeMirror> typeArguments = declaredType.getTypeArguments();
            if (!typeArguments.isEmpty())
            {
                result.append("<");
                for (int i = 0; i < typeArguments.size(); i++)
                {
                    if (i != 0)
                    {
                        result.append(", ");
                    }

                    // NOTE: Recursively resolve the types
                    typeToString(typeArguments.get(i), result, innerClassSeparator);
                }

                result.append(">");
            }

            return null;
        }

        @Override
        public Void visitPrimitive(PrimitiveType primitiveType, Void v) { ... }

        @Override
        public Void visitArray(ArrayType arrayType, Void v) { ... }

        @Override
        public Void visitTypeVariable(TypeVariable typeVariable, Void v) 
        {
            result.append(typeVariable.asElement().getSimpleName());
            return null;
        }

        @Override
        public Void visitError(ErrorType errorType, Void v) { ... }

        @Override
        protected Void defaultAction(TypeMirror typeMirror, Void v) { ... }
    }, null);
}

I am busy with my own project which generates class extensions. The Dagger method works for complex situations, including generic inner classes. I have the following results:

My test class with field to extend:

public class AnnotationTest
{
    ...

    public static class A
    {
        @MyAnnotation
        private Set<B<Integer>> _bs;
    }

    public static class B<T>
    {
        private T _value;
    }
}

Calling the Dagger method on the Element the processor provides for the _bs field:

accessor.type = DaggerUtils.typeToString(element.asType());

The generated source (custom, of course). Note the awesome nested generic types.

public java.util.Set<AnnotationTest.B<java.lang.Integer>> AnnotationTest.A.getBsGenerated()
{
    return this._bs;
}

EDIT: adapting the concept to extract a TypeMirror of the first generic argument, null otherwise:

public static TypeMirror getGenericType(final TypeMirror type)
{
    final TypeMirror[] result = { null };

    type.accept(new SimpleTypeVisitor6<Void, Void>()
    {
        @Override
        public Void visitDeclared(DeclaredType declaredType, Void v)
        {
            List<? extends TypeMirror> typeArguments = declaredType.getTypeArguments();
            if (!typeArguments.isEmpty())
            {
                result[0] = typeArguments.get(0);
            }
            return null;
        }
        @Override
        public Void visitPrimitive(PrimitiveType primitiveType, Void v)
        {
            return null;
        }
        @Override
        public Void visitArray(ArrayType arrayType, Void v)
        {
            return null;
        }
        @Override
        public Void visitTypeVariable(TypeVariable typeVariable, Void v)
        {
            return null;
        }
        @Override
        public Void visitError(ErrorType errorType, Void v)
        {
            return null;
        }
        @Override
        protected Void defaultAction(TypeMirror typeMirror, Void v)
        {
            throw new UnsupportedOperationException();
        }
    }, null);

    return result[0];
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!