Skip to content

Commit

Permalink
Cleanup `AnnotationHierarchies#hasTransitiveSuperAnnotationType(..)
Browse files Browse the repository at this point in the history
  • Loading branch information
BoykoAlex committed Jun 13, 2024
1 parent 3c49982 commit 0312d53
Show file tree
Hide file tree
Showing 4 changed files with 852 additions and 3 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -139,7 +139,7 @@ public boolean appliesTo(ASTNode node, int offset, CharSequence prefix) {
if (annotations != null) {
for (int i = 0; i < annotations.length; i++) {
ITypeBinding annotationType = annotations[i].getAnnotationType();
if (AnnotationHierarchies.isMetaAnnotation(annotationType, (name) -> requiredAnnotation.equals(name))) {
if (AnnotationHierarchies.hasTransitiveSuperAnnotationType(annotationType, requiredAnnotation)) {
return true;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@

import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Set;
import java.util.function.Predicate;
import java.util.stream.Stream;
Expand Down Expand Up @@ -78,9 +81,49 @@ public static boolean isSubtypeOf(Annotation annotation, String fqAnnotationType

public static boolean hasTransitiveSuperAnnotationType(ITypeBinding typeBinding, String annotationType) {
synchronized(lock) {
return isMetaAnnotation(typeBinding, annotationType::equals);
if (typeBinding != null && annotationType != null) {
for (Iterator<ITypeBinding> itr = metaHierarchy(typeBinding); itr.hasNext();) {
ITypeBinding t = itr.next();
if (annotationType.equals(t.getQualifiedName())) {
return true;
}
}
}
return false;
}
}

public static Iterator<ITypeBinding> metaHierarchy(ITypeBinding actualAnnotation) {
return new Iterator<>() {

private HashSet<String> seen = new HashSet<>();
private Queue<ITypeBinding> queue = new LinkedList<>();

{
seen.add(actualAnnotation.getQualifiedName());
queue.add(actualAnnotation);
}

@Override
public boolean hasNext() {
return !queue.isEmpty();
}

@Override
public ITypeBinding next() {
ITypeBinding next = queue.poll();
for (ITypeBinding a : getDirectSuperAnnotations(next)) {
String qName = a.getQualifiedName();
if (!seen.contains(qName)) {
seen.add(qName);
queue.add(a);
}
}
return next;
}

};
}

public static Collection<ITypeBinding> getMetaAnnotations(ITypeBinding actualAnnotation, Predicate<String> isKeyAnnotationName) {
synchronized(lock) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ public boolean visit(MarkerAnnotation node) {

assertThat(AnnotationHierarchies.hasTransitiveSuperAnnotationType(binding, "test.CustomComponent2")).isTrue();
assertThat(AnnotationHierarchies.hasTransitiveSuperAnnotationType(binding, "org.springframework.context.annotation.Configuration")).isFalse();
assertThat(AnnotationHierarchies.isMetaAnnotation(binding, "test.CustomComponent2"::equals)).isTrue();
assertThat(AnnotationHierarchies.getMetaAnnotations(binding, qn -> true).stream().toList().size()).isEqualTo(3);
assertThat(AnnotationHierarchies.isMetaAnnotation(binding, "org.springframework.context.annotation.Configuration"::equals)).isFalse();
assertThat(AnnotationHierarchies.getDirectSuperAnnotations(binding).stream().toList().size()).isEqualTo(2);

Expand All @@ -129,4 +129,56 @@ public boolean visit(MarkerAnnotation node) {
}, null);

}

@Test
void simpleHierarchy() throws Exception {
String projectName = "test-spring-validations";
IJavaProject project = ProjectsHarness.INSTANCE.mavenProject(projectName);
Path file = createFile(projectName, "test", "MyComponent.java", """
package test;
import org.springframework.boot.autoconfigure.SpringBootApplication
@SpringBootApplication
public class MyComponent {
}
""");

SpringIndexerJava.createParser(project, true).createASTs(new String[] { file.toFile().toString() }, null, new String[0], new FileASTRequestor() {
@Override
public void acceptAST(String sourceFilePath, CompilationUnit cu) {
cu.accept(new ASTVisitor() {

@Override
public boolean visit(MarkerAnnotation node) {
ITypeBinding binding = node.resolveTypeBinding();
assertThat(binding).isNotNull();
assertThat(binding.getQualifiedName()).isEqualTo("org.springframework.boot.autoconfigure.SpringBootApplication");

assertThat(AnnotationHierarchies.hasTransitiveSuperAnnotationType(binding, "test.CustomComponent2")).isFalse();
assertThat(AnnotationHierarchies.hasTransitiveSuperAnnotationType(binding, "org.springframework.context.annotation.Configuration")).isTrue();
assertThat(AnnotationHierarchies.hasTransitiveSuperAnnotationType(binding, "org.springframework.boot.autoconfigure.SpringBootApplication")).isTrue();
assertThat(AnnotationHierarchies.hasTransitiveSuperAnnotationType(binding, "org.springframework.stereotype.Component")).isTrue();
List<ITypeBinding> metaAnnotations = AnnotationHierarchies.getMetaAnnotations(binding, qn -> true).stream().toList();
assertThat(metaAnnotations.size()).isEqualTo(8);
assertThat(AnnotationHierarchies.isMetaAnnotation(binding, "org.springframework.context.annotation.Configuration"::equals)).isTrue();
assertThat(AnnotationHierarchies.getDirectSuperAnnotations(binding).stream().toList().size()).isEqualTo(3);

IAnnotationBinding annotationBinding = node.resolveAnnotationBinding();
assertThat(annotationBinding).isNotNull();
assertThat(AnnotationHierarchies.getDirectSuperAnnotationBindings(annotationBinding).stream().toList().size()).isEqualTo(3);
assertThat(AnnotationHierarchies.isSubtypeOf(node, "test.CustomComponent2")).isFalse();
assertThat(AnnotationHierarchies.isSubtypeOf(node, "org.springframework.context.annotation.Configuration")).isTrue();
assertThat(AnnotationHierarchies.isSubtypeOf(node, "org.springframework.boot.autoconfigure.SpringBootApplication")).isTrue();
assertThat(AnnotationHierarchies.isSubtypeOf(node, "org.springframework.stereotype.Component")).isTrue();
return super.visit(node);
}

});
}
}, null);

}

}
Loading

0 comments on commit 0312d53

Please sign in to comment.