GH-1375: added check to not show bean names as qualifier proposals on bean methods
This commit is contained in:
@@ -12,11 +12,14 @@ package org.springframework.ide.vscode.boot.java.beans;
|
||||
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.eclipse.jdt.core.dom.ASTNode;
|
||||
import org.eclipse.jdt.core.dom.Annotation;
|
||||
import org.eclipse.jdt.core.dom.IAnnotationBinding;
|
||||
import org.eclipse.jdt.core.dom.MethodDeclaration;
|
||||
import org.eclipse.jdt.core.dom.TypeDeclaration;
|
||||
import org.springframework.ide.vscode.boot.index.SpringMetamodelIndex;
|
||||
@@ -42,9 +45,10 @@ public class QualifierCompletionProvider implements AnnotationAttributeCompletio
|
||||
Bean[] beans = this.springIndex.getBeansOfProject(project.getElementName());
|
||||
|
||||
boolean isOnType = isAnnotationOnType(node);
|
||||
boolean isOnBeanMethod = isOnBeanMethod(node);
|
||||
|
||||
Stream<String> candidates = findAllQualifiers(beans);
|
||||
if (!isOnType) {
|
||||
if (!isOnType && !isOnBeanMethod) {
|
||||
candidates = Stream.concat(candidates, Arrays.stream(beans).map(bean -> bean.getName()));
|
||||
}
|
||||
|
||||
@@ -89,5 +93,44 @@ public class QualifierCompletionProvider implements AnnotationAttributeCompletio
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean isOnBeanMethod(ASTNode node) {
|
||||
Annotation annotation = findAnnotation(node);
|
||||
if (annotation != null) {
|
||||
if (annotation.getParent() instanceof MethodDeclaration) {
|
||||
MethodDeclaration method = (MethodDeclaration) annotation.getParent();
|
||||
return hasBeanAnnotation(method);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private boolean hasBeanAnnotation(MethodDeclaration method) {
|
||||
List<?> modifiers = method.modifiers();
|
||||
for (Object modifier : modifiers) {
|
||||
if (modifier instanceof Annotation) {
|
||||
Annotation annotation = (Annotation) modifier;
|
||||
IAnnotationBinding annotationBinding = annotation.resolveAnnotationBinding();
|
||||
String type = annotationBinding.getAnnotationType().getBinaryName();
|
||||
|
||||
if (type != null && Annotations.BEAN.equals(type)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private Annotation findAnnotation(ASTNode node) {
|
||||
while (node != null) {
|
||||
if (node instanceof Annotation) {
|
||||
return (Annotation) node;
|
||||
}
|
||||
node = node.getParent();
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -96,86 +96,106 @@ public class QualifierCompletionProviderTest {
|
||||
|
||||
@Test
|
||||
public void testQualifierCompletionWithoutQuotesWithoutPrefixAtInjecitonPoint() throws Exception {
|
||||
assertCompletions("@Qualifier(<*>)", new String[] {"quali1", "quali2", "bean1", "bean2"}, 0, "@Qualifier(\"quali1\"<*>)", false);
|
||||
assertCompletions("@Qualifier(<*>)", new String[] {"quali1", "quali2", "bean1", "bean2"}, 0, "@Qualifier(\"quali1\"<*>)", PositionInCode.ON_INJECTION_POINT);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQualifierCompletionWithoutQuotesWithoutPrefixAtTypeDeclaration() throws Exception {
|
||||
assertCompletions("@Qualifier(<*>)", new String[] {"quali1", "quali2"}, 0, "@Qualifier(\"quali1\"<*>)", true);
|
||||
assertCompletions("@Qualifier(<*>)", new String[] {"quali1", "quali2"}, 0, "@Qualifier(\"quali1\"<*>)", PositionInCode.ON_TYPE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQualifierCompletionWithoutQuotesWithoutPrefixAtBeanMethod() throws Exception {
|
||||
assertCompletions("@Qualifier(<*>)", new String[] {"quali1", "quali2"}, 0, "@Qualifier(\"quali1\"<*>)", PositionInCode.ON_BEAN_METHOD);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQualifierCompletionWithoutQuotesWithPrefixAtInjecitonPoint() throws Exception {
|
||||
assertCompletions("@Qualifier(be<*>)", 2, "@Qualifier(\"bean1\"<*>)", false);
|
||||
assertCompletions("@Qualifier(be<*>)", 2, "@Qualifier(\"bean1\"<*>)", PositionInCode.ON_INJECTION_POINT);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQualifierCompletionWithoutQuotesWithPrefixAtTypeDeclaration() throws Exception {
|
||||
assertCompletions("@Qualifier(be<*>)", 0, null, PositionInCode.ON_TYPE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQualifierCompletionWithoutQuotesWithPrefixAtBeanMethod() throws Exception {
|
||||
assertCompletions("@Qualifier(be<*>)", 0, null, PositionInCode.ON_BEAN_METHOD);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQualifierCompletionWithoutQuotesWithPrefixFromExistingQualifierAtInjecitonPoint() throws Exception {
|
||||
assertCompletions("@Qualifier(qu<*>)", new String[] {"quali1", "quali2"}, 0, "@Qualifier(\"quali1\"<*>)", false);
|
||||
assertCompletions("@Qualifier(qu<*>)", new String[] {"quali1", "quali2"}, 0, "@Qualifier(\"quali1\"<*>)", PositionInCode.ON_INJECTION_POINT);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Disabled // TODO: implement this case
|
||||
public void testQualifierCompletionWithoutQuotesWithAttributeNameAtInjecitonPoint() throws Exception {
|
||||
assertCompletions("@Qualifier(value=<*>)", 4, "@Qualifier(value=\"quali1\"<*>)", false);
|
||||
assertCompletions("@Qualifier(value=<*>)", 4, "@Qualifier(value=\"quali1\"<*>)", PositionInCode.ON_INJECTION_POINT);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQualifierCompletionWithoutQuotesWithAttributeNameAtTypeDeclaration() throws Exception {
|
||||
assertCompletions("@Qualifier(value=<*>)", 2, "@Qualifier(value=\"quali1\"<*>)", true);
|
||||
assertCompletions("@Qualifier(value=<*>)", 2, "@Qualifier(value=\"quali1\"<*>)", PositionInCode.ON_TYPE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQualifierCompletionWithoutQuotesWithAttributeNameAtBeanMethod() throws Exception {
|
||||
assertCompletions("@Qualifier(value=<*>)", 2, "@Qualifier(value=\"quali1\"<*>)", PositionInCode.ON_BEAN_METHOD);
|
||||
}
|
||||
|
||||
@Test
|
||||
@Disabled // TODO: implement this case
|
||||
public void testQualifierCompletionWithoutQuotesWithAttributeNameAndSpacesAtInjecitonPoint() throws Exception {
|
||||
assertCompletions("@Qualifier(value = <*>)", 4, "@Qualifier(value = \"quali1\"<*>)", false);
|
||||
assertCompletions("@Qualifier(value = <*>)", 4, "@Qualifier(value = \"quali1\"<*>)", PositionInCode.ON_INJECTION_POINT);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQualifierCompletionWithoutQuotesWithAttributeNameAndSpacesAtTypeDeclaration() throws Exception {
|
||||
assertCompletions("@Qualifier(value = <*>)", 2, "@Qualifier(value = \"quali1\"<*>)", true);
|
||||
assertCompletions("@Qualifier(value = <*>)", 2, "@Qualifier(value = \"quali1\"<*>)", PositionInCode.ON_TYPE);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQualifierCompletionInsideOfQuotesWithoutPrefixAtInjecitonPoint() throws Exception {
|
||||
assertCompletions("@Qualifier(\"<*>\")", 4, "@Qualifier(\"quali1<*>\")", false);
|
||||
assertCompletions("@Qualifier(\"<*>\")", 4, "@Qualifier(\"quali1<*>\")", PositionInCode.ON_INJECTION_POINT);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQualifierCompletionInsideOfQuotesWithPrefixAtInjecitonPoint() throws Exception {
|
||||
assertCompletions("@Qualifier(\"be<*>\")", 2, "@Qualifier(\"bean1<*>\")", false);
|
||||
assertCompletions("@Qualifier(\"be<*>\")", 2, "@Qualifier(\"bean1<*>\")", PositionInCode.ON_INJECTION_POINT);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQualifierCompletionInsideOfQuotesWithPrefixButWithoutMatchesAtInjecitonPoint() throws Exception {
|
||||
assertCompletions("@Qualifier(\"XXX<*>\")", 0, null, false);
|
||||
assertCompletions("@Qualifier(\"XXX<*>\")", 0, null, PositionInCode.ON_INJECTION_POINT);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQualifierCompletionOutsideOfAnnotation1AtInjecitonPoint() throws Exception {
|
||||
assertCompletions("@Qualifier(\"XXX\")<*>", 0, null, false);
|
||||
assertCompletions("@Qualifier(\"XXX\")<*>", 0, null, PositionInCode.ON_INJECTION_POINT);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQualifierCompletionOutsideOfAnnotation2AtInjecitonPoint() throws Exception {
|
||||
assertCompletions("@Qualifier<*>(\"XXX\")", 0, null, false);
|
||||
assertCompletions("@Qualifier<*>(\"XXX\")", 0, null, PositionInCode.ON_INJECTION_POINT);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testQualifierCompletionInsideOfQuotesWithPrefixAndReplacedPostfixAtInjecitonPoint() throws Exception {
|
||||
assertCompletions("@Qualifier(\"be<*>xxx\")", 2, "@Qualifier(\"bean1<*>\")", false);
|
||||
assertCompletions("@Qualifier(\"be<*>xxx\")", 2, "@Qualifier(\"bean1<*>\")", PositionInCode.ON_INJECTION_POINT);
|
||||
}
|
||||
|
||||
private void assertCompletions(String completionLine, int noOfExpectedCompletions, String expectedCompletedLine, boolean onType) throws Exception {
|
||||
assertCompletions(completionLine, noOfExpectedCompletions, null, 0, expectedCompletedLine, onType);
|
||||
private void assertCompletions(String completionLine, int noOfExpectedCompletions, String expectedCompletedLine, PositionInCode position) throws Exception {
|
||||
assertCompletions(completionLine, noOfExpectedCompletions, null, 0, expectedCompletedLine, position);
|
||||
}
|
||||
|
||||
private void assertCompletions(String completionLine, String[] expectedCompletions, int chosenCompletion, String expectedCompletedLine, boolean onType) throws Exception {
|
||||
assertCompletions(completionLine, expectedCompletions.length, expectedCompletions, chosenCompletion, expectedCompletedLine, onType);
|
||||
private void assertCompletions(String completionLine, String[] expectedCompletions, int chosenCompletion, String expectedCompletedLine, PositionInCode position) throws Exception {
|
||||
assertCompletions(completionLine, expectedCompletions.length, expectedCompletions, chosenCompletion, expectedCompletedLine, position);
|
||||
}
|
||||
|
||||
private void assertCompletions(String completionLine, int noOfExcpectedCompletions, String[] expectedCompletions, int chosenCompletion, String expectedCompletedLine, boolean onType) throws Exception {
|
||||
String editorContent = createEditorContent(completionLine, onType);
|
||||
private void assertCompletions(String completionLine, int noOfExcpectedCompletions, String[] expectedCompletions, int chosenCompletion, String expectedCompletedLine, PositionInCode position) throws Exception {
|
||||
String editorContent = createEditorContent(completionLine, position);
|
||||
Editor editor = harness.newEditor(LanguageId.JAVA, editorContent, tempJavaDocUri);
|
||||
|
||||
List<CompletionItem> completions = editor.getCompletions();
|
||||
@@ -191,12 +211,13 @@ public class QualifierCompletionProviderTest {
|
||||
|
||||
if (noOfExcpectedCompletions > 0) {
|
||||
editor.apply(completions.get(chosenCompletion));
|
||||
assertEquals(createEditorContent(expectedCompletedLine, onType), editor.getText());
|
||||
assertEquals(createEditorContent(expectedCompletedLine, position), editor.getText());
|
||||
}
|
||||
}
|
||||
|
||||
private String createEditorContent(String placeholderValue, boolean onType) {
|
||||
if (onType) {
|
||||
private String createEditorContent(String placeholderValue, PositionInCode position) {
|
||||
switch (position) {
|
||||
case ON_TYPE:
|
||||
return """
|
||||
package org.test;
|
||||
|
||||
@@ -210,8 +231,7 @@ public class QualifierCompletionProviderTest {
|
||||
public class TestDependsOnClass {
|
||||
}
|
||||
""";
|
||||
}
|
||||
else {
|
||||
case ON_INJECTION_POINT:
|
||||
return """
|
||||
package org.test;
|
||||
|
||||
@@ -227,8 +247,34 @@ public class QualifierCompletionProviderTest {
|
||||
|
||||
}
|
||||
""";
|
||||
case ON_BEAN_METHOD:
|
||||
return """
|
||||
package org.test;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.beans.factory.annotation.Qualifier;
|
||||
|
||||
@Configuration
|
||||
public class TestDependsOnClass {
|
||||
|
||||
@Bean
|
||||
""" +
|
||||
placeholderValue + "\n" +
|
||||
"""
|
||||
public Object myBean() {
|
||||
return new Object();
|
||||
}
|
||||
|
||||
}
|
||||
""";
|
||||
default: return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static enum PositionInCode {
|
||||
ON_TYPE, ON_BEAN_METHOD, ON_INJECTION_POINT
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user