我正在编写一个使用注释处理器生成源代码的工具,具体取决于带注释类的方法的返回类型。返回类型始终是接口A
的某个子类型(接口或类),它定义了类型变量T
。
interface A<T>{T m();};
我想找到方法m()
返回值类型变量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
是javax.lang.model.type.DeclaredType
,T
是第一个类型参数。结果t
是javax.lang.model.type.TypeVariable
的{{1}}。对于具体的返回类型T
(A<B>
),同样适用于某种类型:B
)。 interface B{}
的结果是代表t
的{{1}}。
其他结果类型开始变得复杂:
DeclaredType
B
有没有办法在不镜像整个java类型系统的情况下为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{}
找到正确的类型参数?
答案 0 :(得分:6)
我用它来解决这个问题,并在此拉取请求中为WsDoc项目提供了解决方案:https://github.com/versly/wsdoc/pull/7
我做了类似的事情:
Type.MethodType methodType = (Type.MethodType) processingEnv.getTypeUtils().asMemberOf(declaredTypeThatExtendsSomeGenericParent, methodToGetReturnTypeForAsExecutableElement);
TypeMirror type = methodType.getReturnType();
答案 1 :(得分: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);
}
}
}
}
答案 2 :(得分:3)
这似乎是一个常见的问题,对于那些来自谷歌的人来说:有希望。
Dagger DI项目根据Apache 2.0许可证授权,并包含一些实用程序方法,用于处理注释处理器中的类型。
特别是,可以在GitHub(Util.java)上完整查看Util
类,并定义方法public static String typeToString(TypeMirror type)
。它使用TypeVisitor和一些递归调用来构建类型的字符串表示。这是一个参考片段:
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);
}
我忙于自己的项目,它会生成类扩展。 Dagger方法适用于复杂情况,包括通用内部类。我有以下结果:
我的测试类包含要扩展的字段:
public class AnnotationTest
{
...
public static class A
{
@MyAnnotation
private Set<B<Integer>> _bs;
}
public static class B<T>
{
private T _value;
}
}
在Element
处理器上调用Dagger方法提供_bs
字段:
accessor.type = DaggerUtils.typeToString(element.asType());
生成的源(当然是自定义的)。请注意令人敬畏的嵌套泛型类型。
public java.util.Set<AnnotationTest.B<java.lang.Integer>> AnnotationTest.A.getBsGenerated()
{
return this._bs;
}
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];
}