Skip to content

Commit 3b95268

Browse files
committed
GH-1375: added check to not show bean names as qualifier proposals on type declarations
1 parent 2dffa3a commit 3b95268

File tree

2 files changed

+103
-48
lines changed

2 files changed

+103
-48
lines changed

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

Lines changed: 25 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
import org.eclipse.jdt.core.dom.ASTNode;
2020
import org.eclipse.jdt.core.dom.MethodDeclaration;
21+
import org.eclipse.jdt.core.dom.TypeDeclaration;
2122
import org.springframework.ide.vscode.boot.index.SpringMetamodelIndex;
2223
import org.springframework.ide.vscode.boot.java.Annotations;
2324
import org.springframework.ide.vscode.boot.java.annotations.AnnotationAttributeCompletionProvider;
@@ -39,16 +40,21 @@ public QualifierCompletionProvider(SpringMetamodelIndex springIndex) {
3940
public Map<String, String> getCompletionCandidates(IJavaProject project, ASTNode node) {
4041

4142
Bean[] beans = this.springIndex.getBeansOfProject(project.getElementName());
43+
44+
boolean isOnType = isAnnotationOnType(node);
4245

43-
return Stream.concat(
44-
findAllQualifiers(beans),
45-
Arrays.stream(beans).map(bean -> bean.getName()))
46+
Stream<String> candidates = findAllQualifiers(beans);
47+
if (!isOnType) {
48+
candidates = Stream.concat(candidates, Arrays.stream(beans).map(bean -> bean.getName()));
49+
}
50+
51+
return candidates
4652
.distinct()
4753
.collect(Collectors.toMap(key -> key, value -> value, (u, v) -> u, LinkedHashMap::new));
4854
}
4955

5056
private Stream<String> findAllQualifiers(Bean[] beans) {
51-
57+
5258
Stream<String> qualifiersFromBeans = Arrays.stream(beans)
5359
// annotations from beans themselves
5460
.flatMap(bean -> Arrays.stream(bean.getAnnotations()))
@@ -69,4 +75,19 @@ private Stream<String> findAllQualifiers(Bean[] beans) {
6975
return Stream.concat(qualifiersFromBeans, qualifiersFromInjectionPoints);
7076
}
7177

78+
private boolean isAnnotationOnType(ASTNode node) {
79+
while (node != null) {
80+
if (node instanceof MethodDeclaration) {
81+
return false;
82+
}
83+
else if (node instanceof TypeDeclaration) {
84+
return true;
85+
}
86+
87+
node = node.getParent();
88+
}
89+
90+
return false;
91+
}
92+
7293
}

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

Lines changed: 78 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import org.eclipse.lsp4j.TextDocumentIdentifier;
2727
import org.junit.jupiter.api.AfterEach;
2828
import org.junit.jupiter.api.BeforeEach;
29+
import org.junit.jupiter.api.Disabled;
2930
import org.junit.jupiter.api.Test;
3031
import org.junit.jupiter.api.extension.ExtendWith;
3132
import org.springframework.beans.factory.annotation.Autowired;
@@ -94,78 +95,87 @@ public void restoreIndexState() {
9495
}
9596

9697
@Test
97-
public void testQualifierCompletionWithoutQuotesWithoutPrefix() throws Exception {
98-
assertCompletions("@Qualifier(<*>)", new String[] {"quali1", "quali2", "bean1", "bean2"}, 0, "@Qualifier(\"quali1\"<*>)");
98+
public void testQualifierCompletionWithoutQuotesWithoutPrefixAtInjecitonPoint() throws Exception {
99+
assertCompletions("@Qualifier(<*>)", new String[] {"quali1", "quali2", "bean1", "bean2"}, 0, "@Qualifier(\"quali1\"<*>)", false);
99100
}
100101

101102
@Test
102-
public void testQualifierCompletionWithoutQuotesWithPrefix() throws Exception {
103-
assertCompletions("@Qualifier(be<*>)", 2, "@Qualifier(\"bean1\"<*>)");
103+
public void testQualifierCompletionWithoutQuotesWithoutPrefixAtTypeDeclaration() throws Exception {
104+
assertCompletions("@Qualifier(<*>)", new String[] {"quali1", "quali2"}, 0, "@Qualifier(\"quali1\"<*>)", true);
104105
}
105106

106107
@Test
107-
public void testQualifierCompletionWithoutQuotesWithPrefixFromExistingQualifier() throws Exception {
108-
assertCompletions("@Qualifier(qu<*>)", new String[] {"quali1", "quali2"}, 0, "@Qualifier(\"quali1\"<*>)");
108+
public void testQualifierCompletionWithoutQuotesWithPrefixAtInjecitonPoint() throws Exception {
109+
assertCompletions("@Qualifier(be<*>)", 2, "@Qualifier(\"bean1\"<*>)", false);
109110
}
110111

111112
@Test
112-
public void testQualifierCompletionWithoutQuotesWithAttributeName() throws Exception {
113-
assertCompletions("@Qualifier(value=<*>)", 4, "@Qualifier(value=\"quali1\"<*>)");
113+
public void testQualifierCompletionWithoutQuotesWithPrefixFromExistingQualifierAtInjecitonPoint() throws Exception {
114+
assertCompletions("@Qualifier(qu<*>)", new String[] {"quali1", "quali2"}, 0, "@Qualifier(\"quali1\"<*>)", false);
114115
}
115116

116117
@Test
117-
public void testQualifierCompletionInsideOfQuotesWithoutPrefix() throws Exception {
118-
assertCompletions("@Qualifier(\"<*>\")", 4, "@Qualifier(\"quali1<*>\")");
118+
@Disabled // TODO: implement this case
119+
public void testQualifierCompletionWithoutQuotesWithAttributeNameAtInjecitonPoint() throws Exception {
120+
assertCompletions("@Qualifier(value=<*>)", 4, "@Qualifier(value=\"quali1\"<*>)", false);
119121
}
120122

121123
@Test
122-
public void testQualifierCompletionInsideOfQuotesWithPrefix() throws Exception {
123-
assertCompletions("@Qualifier(\"be<*>\")", 2, "@Qualifier(\"bean1<*>\")");
124+
public void testQualifierCompletionWithoutQuotesWithAttributeNameAtTypeDeclaration() throws Exception {
125+
assertCompletions("@Qualifier(value=<*>)", 2, "@Qualifier(value=\"quali1\"<*>)", true);
124126
}
125127

126128
@Test
127-
public void testQualifierCompletionInsideOfQuotesWithPrefixButWithoutMatches() throws Exception {
128-
assertCompletions("@Qualifier(\"XXX<*>\")", 0, null);
129+
@Disabled // TODO: implement this case
130+
public void testQualifierCompletionWithoutQuotesWithAttributeNameAndSpacesAtInjecitonPoint() throws Exception {
131+
assertCompletions("@Qualifier(value = <*>)", 4, "@Qualifier(value = \"quali1\"<*>)", false);
129132
}
130133

131134
@Test
132-
public void testQualifierCompletionOutsideOfAnnotation1() throws Exception {
133-
assertCompletions("@Qualifier(\"XXX\")<*>", 0, null);
135+
public void testQualifierCompletionWithoutQuotesWithAttributeNameAndSpacesAtTypeDeclaration() throws Exception {
136+
assertCompletions("@Qualifier(value = <*>)", 2, "@Qualifier(value = \"quali1\"<*>)", true);
134137
}
135138

136139
@Test
137-
public void testQualifierCompletionOutsideOfAnnotation2() throws Exception {
138-
assertCompletions("@Qualifier<*>(\"XXX\")", 0, null);
140+
public void testQualifierCompletionInsideOfQuotesWithoutPrefixAtInjecitonPoint() throws Exception {
141+
assertCompletions("@Qualifier(\"<*>\")", 4, "@Qualifier(\"quali1<*>\")", false);
139142
}
140143

141144
@Test
142-
public void testQualifierCompletionInsideOfQuotesWithPrefixAndReplacedPostfix() throws Exception {
143-
assertCompletions("@Qualifier(\"be<*>xxx\")", 2, "@Qualifier(\"bean1<*>\")");
145+
public void testQualifierCompletionInsideOfQuotesWithPrefixAtInjecitonPoint() throws Exception {
146+
assertCompletions("@Qualifier(\"be<*>\")", 2, "@Qualifier(\"bean1<*>\")", false);
144147
}
145-
146-
private void assertCompletions(String completionLine, int noOfExpectedCompletions, String expectedCompletedLine) throws Exception {
147-
assertCompletions(completionLine, noOfExpectedCompletions, null, 0, expectedCompletedLine);
148+
149+
@Test
150+
public void testQualifierCompletionInsideOfQuotesWithPrefixButWithoutMatchesAtInjecitonPoint() throws Exception {
151+
assertCompletions("@Qualifier(\"XXX<*>\")", 0, null, false);
148152
}
149153

150-
private void assertCompletions(String completionLine, String[] expectedCompletions, int chosenCompletion, String expectedCompletedLine) throws Exception {
151-
assertCompletions(completionLine, expectedCompletions.length, expectedCompletions, chosenCompletion, expectedCompletedLine);
154+
@Test
155+
public void testQualifierCompletionOutsideOfAnnotation1AtInjecitonPoint() throws Exception {
156+
assertCompletions("@Qualifier(\"XXX\")<*>", 0, null, false);
152157
}
153158

154-
private void assertCompletions(String completionLine, int noOfExcpectedCompletions, String[] expectedCompletions, int chosenCompletion, String expectedCompletedLine) throws Exception {
155-
String editorContent = """
156-
package org.test;
159+
@Test
160+
public void testQualifierCompletionOutsideOfAnnotation2AtInjecitonPoint() throws Exception {
161+
assertCompletions("@Qualifier<*>(\"XXX\")", 0, null, false);
162+
}
157163

158-
import org.springframework.stereotype.Component;
159-
import org.springframework.beans.factory.annotation.Qualifier;
164+
@Test
165+
public void testQualifierCompletionInsideOfQuotesWithPrefixAndReplacedPostfixAtInjecitonPoint() throws Exception {
166+
assertCompletions("@Qualifier(\"be<*>xxx\")", 2, "@Qualifier(\"bean1<*>\")", false);
167+
}
168+
169+
private void assertCompletions(String completionLine, int noOfExpectedCompletions, String expectedCompletedLine, boolean onType) throws Exception {
170+
assertCompletions(completionLine, noOfExpectedCompletions, null, 0, expectedCompletedLine, onType);
171+
}
160172

161-
@Component
162-
""" +
163-
completionLine + "\n" +
164-
"""
165-
public class TestDependsOnClass {
166-
}
167-
""";
168-
173+
private void assertCompletions(String completionLine, String[] expectedCompletions, int chosenCompletion, String expectedCompletedLine, boolean onType) throws Exception {
174+
assertCompletions(completionLine, expectedCompletions.length, expectedCompletions, chosenCompletion, expectedCompletedLine, onType);
175+
}
176+
177+
private void assertCompletions(String completionLine, int noOfExcpectedCompletions, String[] expectedCompletions, int chosenCompletion, String expectedCompletedLine, boolean onType) throws Exception {
178+
String editorContent = createEditorContent(completionLine, onType);
169179
Editor editor = harness.newEditor(LanguageId.JAVA, editorContent, tempJavaDocUri);
170180

171181
List<CompletionItem> completions = editor.getCompletions();
@@ -181,19 +191,43 @@ public class TestDependsOnClass {
181191

182192
if (noOfExcpectedCompletions > 0) {
183193
editor.apply(completions.get(chosenCompletion));
184-
assertEquals("""
185-
package org.test;
194+
assertEquals(createEditorContent(expectedCompletedLine, onType), editor.getText());
195+
}
196+
}
186197

198+
private String createEditorContent(String placeholderValue, boolean onType) {
199+
if (onType) {
200+
return """
201+
package org.test;
202+
187203
import org.springframework.stereotype.Component;
188204
import org.springframework.beans.factory.annotation.Qualifier;
189-
205+
190206
@Component
191-
""" + expectedCompletedLine + "\n" +
207+
""" +
208+
placeholderValue + "\n" +
192209
"""
193210
public class TestDependsOnClass {
194211
}
195-
""", editor.getText());
196-
}
212+
""";
213+
}
214+
else {
215+
return """
216+
package org.test;
217+
218+
import org.springframework.stereotype.Component;
219+
import org.springframework.beans.factory.annotation.Qualifier;
220+
221+
@Component
222+
public class TestDependsOnClass {
223+
224+
public TestDependsOnClass(""" + placeholderValue + " Object someBean) {" +
225+
"""
226+
}
227+
228+
}
229+
""";
230+
}
197231
}
198232

199233

0 commit comments

Comments
 (0)