diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/annotations/AnnotationHierarchies.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/annotations/AnnotationHierarchies.java index 68c86c917..9ffe85805 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/annotations/AnnotationHierarchies.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/annotations/AnnotationHierarchies.java @@ -14,7 +14,6 @@ import java.util.Collection; import java.util.HashSet; import java.util.Set; import java.util.function.Predicate; -import java.util.stream.Collectors; import java.util.stream.Stream; import org.eclipse.jdt.core.dom.Annotation; @@ -43,11 +42,6 @@ public abstract class AnnotationHierarchies { // due to https://bugs.eclipse.org/bugs/show_bug.cgi?id=571247 private static final Object lock = new Object(); - protected static boolean ignoreAnnotation(String fqname) { - return fqname.startsWith("java."); //mostly intended to capture java.lang.annotation.* types. But really it should be - //safe to ignore any type defined by the JRE since it can't possibly be inheriting from a spring annotation. - }; - public static Collection getDirectSuperAnnotations(ITypeBinding typeBinding) { synchronized(lock) { try { @@ -73,37 +67,35 @@ public abstract class AnnotationHierarchies { return ImmutableList.of(); } } - - public static Set getTransitiveSuperAnnotations(ITypeBinding typeBinding) { - synchronized(lock) { - Set seen = new HashSet<>(); - findTransitiveSupers(typeBinding, seen).collect(Collectors.toList()); - return seen; - } - } - - private static Stream findTransitiveSupers(ITypeBinding typeBinding, Set seen) { - synchronized(lock) { - if (typeBinding != null) { - String qname = typeBinding.getQualifiedName(); - if (seen.add(qname)) { - return Stream.concat( - Stream.of(typeBinding), - getDirectSuperAnnotations(typeBinding).stream().flatMap(superBinding -> findTransitiveSupers(superBinding, seen)) - ); - } - } - return Stream.empty(); - } - } - + public static boolean isSubtypeOf(Annotation annotation, String fqAnnotationTypeName) { synchronized(lock) { ITypeBinding annotationType = annotation.resolveTypeBinding(); - if (annotationType!=null) { - return findTransitiveSupers(annotationType, new HashSet<>()) - .anyMatch(superType -> superType.getQualifiedName().equals(fqAnnotationTypeName)); + return hasTransitiveSuperAnnotationType(annotationType, fqAnnotationTypeName); + + } + } + + public static boolean hasTransitiveSuperAnnotationType(ITypeBinding typeBinding, String annotationType) { + synchronized(lock) { + if (typeBinding != null && annotationType != null) { + String qname = typeBinding.getQualifiedName(); + +// log.info("CHECK ANNOTATION TYPE: " + qname + " / " + annotationType); + + if (annotationType.equals(qname)) { + return true; + } + else { + Collection directSuperAnnotations = getDirectSuperAnnotations(typeBinding); + for (ITypeBinding superAnnotationBinding : directSuperAnnotations) { + if (hasTransitiveSuperAnnotationType(superAnnotationBinding, annotationType)) { + return true; + } + } + } } + return false; } } @@ -151,13 +143,11 @@ public abstract class AnnotationHierarchies { } } - public static Stream findTransitiveSuperAnnotationBindings( - IAnnotationBinding annotationBinding) { + public static Stream findTransitiveSuperAnnotationBindings( IAnnotationBinding annotationBinding) { return internalFindTransitiveSuperAnnotationBindings(annotationBinding, new HashSet<>()); } - public static Stream internalFindTransitiveSuperAnnotationBindings( - IAnnotationBinding annotationBinding, Set seen) { + public static Stream internalFindTransitiveSuperAnnotationBindings(IAnnotationBinding annotationBinding, Set seen) { synchronized (lock) { if (annotationBinding.getAnnotationType() != null) { if (seen.add(annotationBinding.getAnnotationType().getQualifiedName())) { @@ -169,6 +159,25 @@ public abstract class AnnotationHierarchies { return Stream.empty(); } } - + + protected static boolean ignoreAnnotation(String fqname) { + return fqname.startsWith("java."); //mostly intended to capture java.lang.annotation.* types. But really it should be + //safe to ignore any type defined by the JRE since it can't possibly be inheriting from a spring annotation. + } + + private static Stream findTransitiveSupers(ITypeBinding typeBinding, Set seen) { + synchronized(lock) { + if (typeBinding != null) { + String qname = typeBinding.getQualifiedName(); + if (seen.add(qname)) { + return Stream.concat( + Stream.of(typeBinding), + getDirectSuperAnnotations(typeBinding).stream().flatMap(superBinding -> findTransitiveSupers(superBinding, seen)) + ); + } + } + return Stream.empty(); + } + } } diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/data/jpa/queries/QueryJdtAstReconciler.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/data/jpa/queries/QueryJdtAstReconciler.java index f10497a29..c86873178 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/data/jpa/queries/QueryJdtAstReconciler.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/data/jpa/queries/QueryJdtAstReconciler.java @@ -12,7 +12,6 @@ package org.springframework.ide.vscode.boot.java.data.jpa.queries; import java.net.URI; import java.util.List; -import java.util.Set; import org.eclipse.jdt.core.dom.ASTVisitor; import org.eclipse.jdt.core.dom.CompilationUnit; @@ -43,8 +42,7 @@ public class QueryJdtAstReconciler implements JdtAstReconciler { @Override public boolean visit(NormalAnnotation node) { - Set allAnnotations = AnnotationHierarchies.getTransitiveSuperAnnotations(node.resolveTypeBinding()); - if (!allAnnotations.contains(Annotations.DATA_QUERY)) { + if (!AnnotationHierarchies.hasTransitiveSuperAnnotationType(node.resolveTypeBinding(), Annotations.DATA_QUERY)) { return false; } @@ -88,10 +86,10 @@ public class QueryJdtAstReconciler implements JdtAstReconciler { @Override public boolean visit(SingleMemberAnnotation node) { - Set allAnnotations = AnnotationHierarchies.getTransitiveSuperAnnotations(node.resolveTypeBinding()); - if (!allAnnotations.contains(Annotations.DATA_QUERY)) { + if (!AnnotationHierarchies.hasTransitiveSuperAnnotationType(node.resolveTypeBinding(), Annotations.DATA_QUERY)) { return false; } + reconcileExpression(getQueryReconciler(project), node.getValue(), problemCollector); return false; } diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/livehover/ComponentInjectionsHoverProvider.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/livehover/ComponentInjectionsHoverProvider.java index e179d7961..3c393b0bc 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/livehover/ComponentInjectionsHoverProvider.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/livehover/ComponentInjectionsHoverProvider.java @@ -14,7 +14,6 @@ import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Optional; -import java.util.Set; import org.eclipse.jdt.core.Flags; import org.eclipse.jdt.core.dom.ASTNode; @@ -183,7 +182,7 @@ public class ComponentInjectionsHoverProvider extends AbstractInjectedIntoHoverP for (Object modifier : modifiers) { if (modifier instanceof Annotation) { ITypeBinding typeBinding = ((Annotation) modifier).resolveTypeBinding(); - if (isComponentAnnotation(typeBinding)) { + if (AnnotationHierarchies.hasTransitiveSuperAnnotationType(typeBinding, Annotations.COMPONENT)) { return true; } } @@ -191,15 +190,4 @@ public class ComponentInjectionsHoverProvider extends AbstractInjectedIntoHoverP return false; } - private boolean isComponentAnnotation(ITypeBinding type) { - Set transitiveSuperAnnotations = AnnotationHierarchies.getTransitiveSuperAnnotations(type); - for (String annotationType : transitiveSuperAnnotations) { - if (Annotations.COMPONENT.equals(annotationType)) { - return true; - } - } - - return false; - } - } diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/reconcilers/AnnotationParamReconciler.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/reconcilers/AnnotationParamReconciler.java index 1a4bff9db..92afc54be 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/reconcilers/AnnotationParamReconciler.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/reconcilers/AnnotationParamReconciler.java @@ -12,7 +12,6 @@ package org.springframework.ide.vscode.boot.java.reconcilers; import java.net.URI; import java.util.List; -import java.util.Set; import org.eclipse.jdt.core.dom.Annotation; import org.eclipse.jdt.core.dom.Expression; @@ -50,7 +49,7 @@ public class AnnotationParamReconciler implements AnnotationReconciler { if (node instanceof SingleMemberAnnotation) { visitSingleMemberAnnotation((SingleMemberAnnotation) node, typeBinding, problemCollector); } else if (node instanceof NormalAnnotation) { - visitNornalAnnotation((NormalAnnotation) node, typeBinding, problemCollector); + visitNormalAnnotation((NormalAnnotation) node, typeBinding, problemCollector); } } @@ -59,8 +58,7 @@ public class AnnotationParamReconciler implements AnnotationReconciler { return; } - Set allAnnotations = AnnotationHierarchies.getTransitiveSuperAnnotations(typeBinding); - if (!allAnnotations.contains(this.annotationType)) { + if (!AnnotationHierarchies.hasTransitiveSuperAnnotationType(typeBinding, this.annotationType)) { return; } @@ -71,13 +69,12 @@ public class AnnotationParamReconciler implements AnnotationReconciler { } } - protected void visitNornalAnnotation(NormalAnnotation node, ITypeBinding typeBinding, IProblemCollector problemCollector) { + protected void visitNormalAnnotation(NormalAnnotation node, ITypeBinding typeBinding, IProblemCollector problemCollector) { if (paramName == null) { return; } - Set allAnnotations = AnnotationHierarchies.getTransitiveSuperAnnotations(typeBinding); - if (!allAnnotations.contains(this.annotationType)) { + if (!AnnotationHierarchies.hasTransitiveSuperAnnotationType(typeBinding, this.annotationType)) { return; }