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 1afb324a3..2f03d299b 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 @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2017, 2022 Pivotal, Inc. + * Copyright (c) 2017, 2024 Pivotal, Inc. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at @@ -82,16 +82,16 @@ public abstract class AnnotationHierarchies { } } - public static Stream findTransitiveSupers(ITypeBinding typeBinding, Set seen) { + private static Stream findTransitiveSupers(ITypeBinding typeBinding, Set seen) { synchronized(lock) { - String qname = typeBinding.getQualifiedName(); - if (seen.add(qname)) { - return Stream.concat( - Stream.of(typeBinding), - getDirectSuperAnnotations(typeBinding).stream().flatMap(superBinding -> - findTransitiveSupers(superBinding, seen) - ) - ); + 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(); } @@ -153,9 +153,20 @@ public abstract class AnnotationHierarchies { public static Stream findTransitiveSuperAnnotationBindings( IAnnotationBinding annotationBinding) { + return internalFindTransitiveSuperAnnotationBindings(annotationBinding, new HashSet<>()); + } + + public static Stream internalFindTransitiveSuperAnnotationBindings( + IAnnotationBinding annotationBinding, Set seen) { synchronized (lock) { - return Stream.concat(Stream.of(annotationBinding), getDirectSuperAnnotationBindings(annotationBinding) - .stream().flatMap(superBinding -> findTransitiveSuperAnnotationBindings(superBinding))); + if (annotationBinding.getAnnotationType() != null) { + seen.add(annotationBinding.getAnnotationType().getQualifiedName()); + return Stream.concat(Stream.of(annotationBinding), getDirectSuperAnnotationBindings(annotationBinding) + .stream() + .filter(superBinding -> !seen.contains(superBinding.getAnnotationType().getQualifiedName())) + .flatMap(superBinding -> internalFindTransitiveSuperAnnotationBindings(superBinding, seen))); + } + return Stream.empty(); } }