diff --git a/core/src/main/java/com/google/errorprone/refaster/UTemplater.java b/core/src/main/java/com/google/errorprone/refaster/UTemplater.java index 709f821a688..b62ac28f8d6 100644 --- a/core/src/main/java/com/google/errorprone/refaster/UTemplater.java +++ b/core/src/main/java/com/google/errorprone/refaster/UTemplater.java @@ -116,7 +116,7 @@ import java.util.Map; import javax.annotation.Nullable; import javax.lang.model.element.Element; -import javax.lang.model.element.Name; +import javax.lang.model.element.ElementKind; import javax.lang.model.element.TypeElement; import javax.lang.model.type.DeclaredType; import javax.lang.model.type.MirroredTypeException; @@ -919,11 +919,11 @@ public UForAll visitForAll(ForAll type, Void v) { public static ImmutableClassToInstanceMap annotationMap(Symbol symbol) { ImmutableClassToInstanceMap.Builder builder = ImmutableClassToInstanceMap.builder(); for (Compound compound : symbol.getAnnotationMirrors()) { - Name qualifiedAnnotationType = - ((TypeElement) compound.getAnnotationType().asElement()).getQualifiedName(); + String annotationClassName = + classNameFrom((TypeElement) compound.getAnnotationType().asElement()); try { Class annotationClazz = - Class.forName(qualifiedAnnotationType.toString()).asSubclass(Annotation.class); + Class.forName(annotationClassName).asSubclass(Annotation.class); builder.put( (Class) annotationClazz, AnnotationProxyMaker.generateAnnotation(compound, annotationClazz)); @@ -933,4 +933,19 @@ public static ImmutableClassToInstanceMap annotationMap(Symbol symbo } return builder.build(); } + + // Class.forName() needs nested classes as "foo.Bar$Baz$Quux", not "foo.Bar.Baz.Quux" + // (which is what getQualifiedName() returns). + private static String classNameFrom(TypeElement type) { + // Get the full type name (e.g. "foo.Bar.Baz.Quux") before walking up the hierarchy. + String typeName = type.getQualifiedName().toString(); + // Find outermost enclosing type (e.g. "foo.Bar" in our example), possibly several levels up. + // Packages enclose types, so we cannot just wait until we hit null. + while (type.getEnclosingElement().getKind() == ElementKind.CLASS) { + type = (TypeElement) type.getEnclosingElement(); + } + // Start with outermost class name and append remainder of full type name with '.' -> '$' + String className = type.getQualifiedName().toString(); + return className + typeName.substring(className.length()).replace('.', '$'); + } }