Getting the qualified class name of generic type with Java 6 annotation processor

后端 未结 3 952
谎友^
谎友^ 2021-02-13 04:49

I am developing a small code generator using JDK 6\'s Annotation Processing API and am stuck trying to get the actual generic type of a field in the class. To be clearer, let\'

3条回答
  •  春和景丽
    2021-02-13 05:44

    Copy-paste of my original answer:

    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()
        {
            @Override
            public Void visitDeclared(DeclaredType declaredType, Void v)
            {
                TypeElement typeElement = (TypeElement) declaredType.asElement();
    
                rawTypeToString(result, typeElement, innerClassSeparator);
    
                List 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> _bs;
        }
    
        public static class B
        {
            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.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()
        {
            @Override
            public Void visitDeclared(DeclaredType declaredType, Void v)
            {
                List 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];
    }
    

提交回复
热议问题