|
| 1 | +package io.jooby.apt; |
| 2 | + |
| 3 | +import com.sun.tools.javac.code.Symbol; |
| 4 | + |
| 5 | +import javax.annotation.processing.ProcessingEnvironment; |
| 6 | +import javax.annotation.processing.RoundEnvironment; |
| 7 | +import javax.lang.model.element.*; |
| 8 | +import javax.lang.model.type.DeclaredType; |
| 9 | +import javax.lang.model.type.TypeKind; |
| 10 | +import javax.lang.model.type.TypeMirror; |
| 11 | +import javax.lang.model.util.ElementScanner8; |
| 12 | +import javax.lang.model.util.Elements; |
| 13 | +import javax.lang.model.util.Types; |
| 14 | +import java.lang.reflect.Field; |
| 15 | +import java.lang.reflect.Method; |
| 16 | +import java.util.*; |
| 17 | + |
| 18 | +public class JoobyProcessorRoundEnvironment { |
| 19 | + |
| 20 | + private final Elements eltUtils; |
| 21 | + private static Types typeUtils; |
| 22 | + private final Set<? extends Element> rootElements; |
| 23 | + |
| 24 | + JoobyProcessorRoundEnvironment(RoundEnvironment roundEnv, ProcessingEnvironment processingEnv) { |
| 25 | + this.rootElements = roundEnv.getRootElements(); |
| 26 | + this.eltUtils = processingEnv.getElementUtils(); |
| 27 | + this.typeUtils = processingEnv.getTypeUtils(); |
| 28 | + } |
| 29 | + |
| 30 | + public Set<? extends Element> getElementsAnnotatedWith(TypeElement a) { |
| 31 | + |
| 32 | + Set<Element> result = Collections.emptySet(); |
| 33 | + ElementScanner8<Set<Element>, TypeElement> scanner = new AnnotationSetScanner(result); |
| 34 | + |
| 35 | + for (Element element : rootElements) |
| 36 | + result = scanner.scan(element, a); |
| 37 | + |
| 38 | + return result; |
| 39 | + } |
| 40 | + |
| 41 | + // Could be written as a local class inside getElementsAnnotatedWith |
| 42 | + private class AnnotationSetScanner extends |
| 43 | + ElementScanningIncludingTypeParameters<Set<Element>, TypeElement> { |
| 44 | + // Insertion-order preserving set |
| 45 | + private Set<Element> annotatedElements = new LinkedHashSet<>(); |
| 46 | + |
| 47 | + AnnotationSetScanner(Set<Element> defaultSet) { |
| 48 | + super(defaultSet); |
| 49 | + } |
| 50 | + |
| 51 | + @Override |
| 52 | + public Set<Element> scan(Element e, TypeElement annotation) { |
| 53 | + //System.out.println("\t\t" + e); |
| 54 | + for (AnnotationMirror annotMirror : eltUtils.getAllAnnotationMirrors(e)) { |
| 55 | + if (annotation.equals(mirrorAsElement(annotMirror))) { |
| 56 | + annotatedElements.add(e); |
| 57 | + break; |
| 58 | + } |
| 59 | + } |
| 60 | + e.accept(this, annotation); |
| 61 | + return annotatedElements; |
| 62 | + } |
| 63 | + |
| 64 | + } |
| 65 | + |
| 66 | + private static abstract class ElementScanningIncludingTypeParameters<R, P> |
| 67 | + extends ElementScanner8<R, P> { |
| 68 | + |
| 69 | + protected ElementScanningIncludingTypeParameters(R defaultValue) { |
| 70 | + super(defaultValue); |
| 71 | + } |
| 72 | + |
| 73 | + @Override |
| 74 | + public R visitType(TypeElement e, P p) { |
| 75 | + // Type parameters are not considered to be enclosed by a type |
| 76 | + if (e.getSuperclass().getKind() == TypeKind.DECLARED) { |
| 77 | + //System.out.println(e.getSimpleName() + " extends " + e.getSuperclass()); |
| 78 | + TypeElement superElement = (TypeElement) ((DeclaredType) e.getSuperclass()).asElement(); |
| 79 | + List<Element> clonedElements = new ArrayList<>(); |
| 80 | + for(Element enclosedElement : superElement.getEnclosedElements()) { |
| 81 | + if (enclosedElement.getKind() == ElementKind.METHOD && enclosedElement.getAnnotationMirrors().size() > 0) { |
| 82 | + Symbol.MethodSymbol methodSymbol = ((Symbol.MethodSymbol)enclosedElement).clone((Symbol.ClassSymbol)e); |
| 83 | + methodSymbol.appendAttributes( ((Symbol.MethodSymbol)enclosedElement).getAnnotationMirrors() ); |
| 84 | + //System.out.println("\t\t" + m.getEnclosingElement() + "::" + m + " #" + m.getAnnotationMirrors().size()); |
| 85 | + clonedElements.add(methodSymbol); |
| 86 | + } |
| 87 | + } |
| 88 | + scan(clonedElements, p); |
| 89 | + } |
| 90 | + return super.visitType(e, p); |
| 91 | + } |
| 92 | + } |
| 93 | + |
| 94 | + private Element mirrorAsElement(AnnotationMirror annotationMirror) { |
| 95 | + return annotationMirror.getAnnotationType().asElement(); |
| 96 | + } |
| 97 | + |
| 98 | +} |
0 commit comments