Skip to content

Commit 2d86e09

Browse files
committed
GH-1429: do not include bean names from the same method or component
Fixes GH-1429
1 parent 2a11dbf commit 2d86e09

File tree

6 files changed

+263
-32
lines changed

6 files changed

+263
-32
lines changed

headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/beans/BeanUtils.java

Lines changed: 53 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*******************************************************************************
2-
* Copyright (c) 2018 Pivotal, Inc.
2+
* Copyright (c) 2018, 2025 Pivotal, Inc.
33
* All rights reserved. This program and the accompanying materials
44
* are made available under the terms of the Eclipse Public License v1.0
55
* which accompanies this distribution, and is available at
@@ -10,9 +10,61 @@
1010
*******************************************************************************/
1111
package org.springframework.ide.vscode.boot.java.beans;
1212

13+
import java.util.Collection;
14+
import java.util.Optional;
15+
16+
import org.eclipse.jdt.core.dom.ASTNode;
17+
import org.eclipse.jdt.core.dom.Annotation;
18+
import org.eclipse.jdt.core.dom.Expression;
19+
import org.eclipse.jdt.core.dom.MethodDeclaration;
20+
import org.eclipse.jdt.core.dom.StringLiteral;
21+
import org.eclipse.jdt.core.dom.TypeDeclaration;
22+
import org.springframework.ide.vscode.boot.java.utils.ASTUtils;
1323
import org.springframework.ide.vscode.commons.util.StringUtil;
1424

25+
import com.google.common.collect.ImmutableList;
26+
1527
public class BeanUtils {
28+
29+
private static final String[] NAME_ATTRIBUTES = {"value", "name"};
30+
31+
public static String getBeanNameFromComponentAnnotation(Annotation annotation, TypeDeclaration type) {
32+
Optional<Expression> attribute = ASTUtils.getAttribute(annotation, "value");
33+
if (attribute.isPresent()) {
34+
return ASTUtils.getExpressionValueAsString(attribute.get(), (a) -> {});
35+
}
36+
else {
37+
String beanName = type.getName().toString();
38+
return BeanUtils.getBeanNameFromType(beanName);
39+
}
40+
}
41+
42+
public static Collection<String> getBeanNamesFromBeanAnnotation(Annotation node) {
43+
Collection<StringLiteral> beanNameNodes = getBeanNameLiterals(node);
44+
45+
if (beanNameNodes != null && !beanNameNodes.isEmpty()) {
46+
return beanNameNodes.stream().map(nameNode -> ASTUtils.getLiteralValue(nameNode))
47+
.toList();
48+
}
49+
else {
50+
ASTNode parent = node.getParent();
51+
if (parent instanceof MethodDeclaration) {
52+
MethodDeclaration method = (MethodDeclaration) parent;
53+
return ImmutableList.of(method.getName().toString());
54+
}
55+
return ImmutableList.of();
56+
}
57+
}
58+
59+
public static Collection<StringLiteral> getBeanNameLiterals(Annotation node) {
60+
ImmutableList.Builder<StringLiteral> literals = ImmutableList.builder();
61+
for (String attrib : NAME_ATTRIBUTES) {
62+
ASTUtils.getAttribute(node, attrib).ifPresent((valueExp) -> {
63+
literals.addAll(ASTUtils.getExpressionValueAsListOfLiterals(valueExp));
64+
});
65+
}
66+
return literals.build();
67+
}
1668

1769
public static String getBeanNameFromType(String typeName) {
1870
if (StringUtil.hasText(typeName) && typeName.length() > 0 && Character.isUpperCase(typeName.charAt(0))) {

headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/beans/BeansSymbolProvider.java

Lines changed: 1 addition & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,6 @@
6363
public class BeansSymbolProvider extends AbstractSymbolProvider {
6464

6565
private static final Logger log = LoggerFactory.getLogger(BeansSymbolProvider.class);
66-
private static final String[] NAME_ATTRIBUTES = {"value", "name"};
6766

6867
@Override
6968
public void addSymbols(Annotation node, ITypeBinding typeBinding, Collection<ITypeBinding> metaAnnotations, SpringIndexerJavaContext context, TextDocument doc) {
@@ -165,7 +164,7 @@ protected void addSymbolsPass1(TypeDeclaration typeDeclaration, SpringIndexerJav
165164
}
166165

167166
protected Collection<Tuple2<String, DocumentRegion>> getBeanNames(Annotation node, TextDocument doc) {
168-
Collection<StringLiteral> beanNameNodes = getBeanNameLiterals(node);
167+
Collection<StringLiteral> beanNameNodes = BeanUtils.getBeanNameLiterals(node);
169168

170169
if (beanNameNodes != null && !beanNameNodes.isEmpty()) {
171170
ImmutableList.Builder<Tuple2<String,DocumentRegion>> namesAndRegions = ImmutableList.builder();
@@ -204,16 +203,6 @@ public static String beanLabel(boolean isFunctionBean, String beanName, String b
204203
return symbolLabel.toString();
205204
}
206205

207-
protected Collection<StringLiteral> getBeanNameLiterals(Annotation node) {
208-
ImmutableList.Builder<StringLiteral> literals = ImmutableList.builder();
209-
for (String attrib : NAME_ATTRIBUTES) {
210-
ASTUtils.getAttribute(node, attrib).ifPresent((valueExp) -> {
211-
literals.addAll(ASTUtils.getExpressionValueAsListOfLiterals(valueExp));
212-
});
213-
}
214-
return literals.build();
215-
}
216-
217206
protected ITypeBinding getBeanType(MethodDeclaration method) {
218207
return method.getReturnType2().resolveBinding();
219208
}

headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/beans/ComponentSymbolProvider.java

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -13,13 +13,11 @@
1313
import java.util.Arrays;
1414
import java.util.Collection;
1515
import java.util.HashSet;
16-
import java.util.Optional;
1716
import java.util.Set;
1817
import java.util.stream.Collectors;
1918
import java.util.stream.Stream;
2019

2120
import org.eclipse.jdt.core.dom.Annotation;
22-
import org.eclipse.jdt.core.dom.Expression;
2321
import org.eclipse.jdt.core.dom.ITypeBinding;
2422
import org.eclipse.jdt.core.dom.TypeDeclaration;
2523
import org.eclipse.lsp4j.Location;
@@ -82,7 +80,7 @@ protected Tuple.Two<EnhancedSymbolInformation, Bean> createSymbol(Annotation nod
8280

8381
TypeDeclaration type = (TypeDeclaration) node.getParent();
8482

85-
String beanName = getBeanName(node, type);
83+
String beanName = BeanUtils.getBeanNameFromComponentAnnotation(node, type);
8684
ITypeBinding beanType = getBeanType(type);
8785

8886
Location location = new Location(doc.getUri(), doc.toRange(node.getStartPosition(), node.getLength()));
@@ -140,18 +138,6 @@ protected String beanLabel(String searchPrefix, String annotationTypeName, Colle
140138
return symbolLabel.toString();
141139
}
142140

143-
public static String getBeanName(Annotation annotation, TypeDeclaration type) {
144-
Optional<Expression> attribute = ASTUtils.getAttribute(annotation, "value");
145-
if (attribute.isPresent()) {
146-
return ASTUtils.getExpressionValueAsString(attribute.get(), (a) -> {});
147-
}
148-
else {
149-
String beanName = type.getName().toString();
150-
return BeanUtils.getBeanNameFromType(beanName);
151-
}
152-
153-
}
154-
155141
private ITypeBinding getBeanType(TypeDeclaration type) {
156142
return type.resolveBinding();
157143
}

headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/beans/DependsOnCompletionProcessor.java

Lines changed: 23 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*******************************************************************************
2-
* Copyright (c) 2024 Broadcom
2+
* Copyright (c) 2024, 2025 Broadcom
33
* All rights reserved. This program and the accompanying materials
44
* are made available under the terms of the Eclipse Public License v1.0
55
* which accompanies this distribution, and is available at
@@ -11,13 +11,19 @@
1111
package org.springframework.ide.vscode.boot.java.beans;
1212

1313
import java.util.Arrays;
14+
import java.util.Collection;
1415
import java.util.List;
1516
import java.util.stream.Collectors;
1617

1718
import org.eclipse.jdt.core.dom.ASTNode;
19+
import org.eclipse.jdt.core.dom.Annotation;
20+
import org.eclipse.jdt.core.dom.MethodDeclaration;
21+
import org.eclipse.jdt.core.dom.TypeDeclaration;
1822
import org.springframework.ide.vscode.boot.index.SpringMetamodelIndex;
23+
import org.springframework.ide.vscode.boot.java.Annotations;
1924
import org.springframework.ide.vscode.boot.java.annotations.AnnotationAttributeCompletionProvider;
2025
import org.springframework.ide.vscode.boot.java.annotations.AnnotationAttributeProposal;
26+
import org.springframework.ide.vscode.boot.java.utils.ASTUtils;
2127
import org.springframework.ide.vscode.commons.java.IJavaProject;
2228

2329
/**
@@ -239,13 +245,28 @@ public DependsOnCompletionProcessor(SpringMetamodelIndex springIndex) {
239245

240246
@Override
241247
public List<AnnotationAttributeProposal> getCompletionCandidates(IJavaProject project, ASTNode node) {
248+
Collection<String> beanNameFromCodeElement = getBeanNameFromSourceCodePosition(node);
249+
242250
return Arrays.stream(this.springIndex.getBeansOfProject(project.getElementName()))
243251
.map(bean -> bean.getName())
252+
.filter(beanName -> !beanNameFromCodeElement.contains(beanName))
244253
.distinct()
245254
.map(beanName -> new AnnotationAttributeProposal(beanName))
246255
.collect(Collectors.toList());
247256
}
248257

249-
258+
private Collection<String> getBeanNameFromSourceCodePosition(ASTNode node) {
259+
ASTNode parent = node.getParent();
260+
if (parent instanceof MethodDeclaration method) {
261+
Annotation beanAnnotation = ASTUtils.getBeanAnnotation(method);
262+
return BeanUtils.getBeanNamesFromBeanAnnotation(beanAnnotation);
263+
}
264+
else if (parent instanceof TypeDeclaration type) {
265+
Annotation componentAnnotation = ASTUtils.getAnnotation(type, Annotations.COMPONENT);
266+
return List.of(BeanUtils.getBeanNameFromComponentAnnotation(componentAnnotation, type));
267+
}
268+
269+
return List.of();
270+
}
250271

251272
}

headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/ASTUtils.java

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*******************************************************************************
2-
* Copyright (c) 2017, 2024 Pivotal, Inc.
2+
* Copyright (c) 2017, 2025 Pivotal, Inc.
33
* All rights reserved. This program and the accompanying materials
44
* are made available under the terms of the Eclipse Public License v1.0
55
* which accompanies this distribution, and is available at
@@ -24,6 +24,7 @@
2424
import org.eclipse.jdt.core.dom.ASTNode;
2525
import org.eclipse.jdt.core.dom.Annotation;
2626
import org.eclipse.jdt.core.dom.ArrayInitializer;
27+
import org.eclipse.jdt.core.dom.BodyDeclaration;
2728
import org.eclipse.jdt.core.dom.CompilationUnit;
2829
import org.eclipse.jdt.core.dom.Expression;
2930
import org.eclipse.jdt.core.dom.FieldDeclaration;
@@ -320,14 +321,18 @@ public static Optional<String> beanId(List<Object> modifiers) {
320321
}
321322

322323
public static Annotation getBeanAnnotation(MethodDeclaration method) {
324+
return getAnnotation(method, Annotations.BEAN);
325+
}
326+
327+
public static Annotation getAnnotation(BodyDeclaration method, String annotationType) {
323328
List<?> modifiers = method.modifiers();
324329
for (Object modifier : modifiers) {
325330
if (modifier instanceof Annotation) {
326331
Annotation annotation = (Annotation) modifier;
327332
ITypeBinding typeBinding = annotation.resolveTypeBinding();
328333
if (typeBinding != null) {
329334
String fqName = typeBinding.getQualifiedName();
330-
if (Annotations.BEAN.equals(fqName)) {
335+
if (annotationType.equals(fqName)) {
331336
return annotation;
332337
}
333338
}

0 commit comments

Comments
 (0)