From f81f359ccabea19603fc209daa8419f717833109 Mon Sep 17 00:00:00 2001 From: Martin Lippert Date: Fri, 25 Oct 2024 12:35:49 +0200 Subject: [PATCH] GH-1386: labels for bean type proposals show simple class name and fully qualified name in details --- ...nnotationAttributeCompletionProcessor.java | 6 +-- ...AnnotationAttributeCompletionProposal.java | 9 +++-- .../AnnotationAttributeProposal.java | 20 ++++++++++ .../beans/BeanTypesCompletionProcessor.java | 10 ++++- .../test/ConditionalOnBeanCompletionTest.java | 40 +++++++++++++++++++ 5 files changed, 76 insertions(+), 9 deletions(-) diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/annotations/AnnotationAttributeCompletionProcessor.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/annotations/AnnotationAttributeCompletionProcessor.java index 5cf52f94c..360e3a90e 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/annotations/AnnotationAttributeCompletionProcessor.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/annotations/AnnotationAttributeCompletionProcessor.java @@ -136,14 +136,14 @@ public class AnnotationAttributeCompletionProcessor implements CompletionProvide List proposals = completionProvider.getCompletionCandidates(project, node); List filteredProposals = proposals.stream() - .filter(proposal -> proposal.getLabel().toLowerCase().contains(filterPrefix.toLowerCase())) - .filter(proposal -> !alreadyMentionedValues.contains(proposal.getLabel())) + .filter(proposal -> proposal.getFilterText().toLowerCase().contains(filterPrefix.toLowerCase())) + .filter(proposal -> !alreadyMentionedValues.contains(proposal.getFilterText())) .collect(Collectors.toList()); double score = filteredProposals.size(); for (AnnotationAttributeProposal candidate : filteredProposals) { DocumentEdits edits = new DocumentEdits(doc, false); - edits.replace(startOffset, endOffset, createReplacementText.apply(candidate.getLabel())); + edits.replace(startOffset, endOffset, createReplacementText.apply(candidate.getFilterText())); AnnotationAttributeCompletionProposal proposal = new AnnotationAttributeCompletionProposal(edits, candidate, null, score--); diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/annotations/AnnotationAttributeCompletionProposal.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/annotations/AnnotationAttributeCompletionProposal.java index 88c6ca325..b8ca3ebf2 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/annotations/AnnotationAttributeCompletionProposal.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/annotations/AnnotationAttributeCompletionProposal.java @@ -33,14 +33,15 @@ public class AnnotationAttributeCompletionProposal extends ScoreableProposal { this.score = score; } -// public AnnotationAttributeCompletionProposal(DocumentEdits edits, String label, String detail, Renderable documentation, double score) { -// this(edits, new AnnotationAttributeProposal(label, detail), documentation, score); -// } - @Override public String getLabel() { return this.coreProposal.getLabel(); } + + @Override + public String getFilterText() { + return this.coreProposal.getFilterText(); + } @Override public CompletionItemKind getKind() { diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/annotations/AnnotationAttributeProposal.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/annotations/AnnotationAttributeProposal.java index 0eb42c0b2..2d6d54fb7 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/annotations/AnnotationAttributeProposal.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/annotations/AnnotationAttributeProposal.java @@ -10,6 +10,8 @@ *******************************************************************************/ package org.springframework.ide.vscode.boot.java.annotations; +import java.util.Objects; + /** * @author Martin Lippert */ @@ -47,4 +49,22 @@ public class AnnotationAttributeProposal { return filterText; } + @Override + public int hashCode() { + return Objects.hash(detail, filterText, label); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + AnnotationAttributeProposal other = (AnnotationAttributeProposal) obj; + return Objects.equals(detail, other.detail) && Objects.equals(filterText, other.filterText) + && Objects.equals(label, other.label); + } + } diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/beans/BeanTypesCompletionProcessor.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/beans/BeanTypesCompletionProcessor.java index 291d9307d..5341943fb 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/beans/BeanTypesCompletionProcessor.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/beans/BeanTypesCompletionProcessor.java @@ -36,9 +36,15 @@ public class BeanTypesCompletionProcessor implements AnnotationAttributeCompleti public List getCompletionCandidates(IJavaProject project, ASTNode node) { Bean[] beans = this.springIndex.getBeansOfProject(project.getElementName()); return Arrays.stream(beans) - .map(Bean::getType) + .map(bean -> new AnnotationAttributeProposal(getClass(bean.getType()), bean.getType(), bean.getType())) .distinct() - .map(beanType -> new AnnotationAttributeProposal(beanType)) .collect(Collectors.toList()); } + + private String getClass(String type) { + if (type != null && type.lastIndexOf('.') >= 0) { + return type.substring(type.lastIndexOf('.') + 1); + } + return type; + } } diff --git a/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/conditionalonbean/test/ConditionalOnBeanCompletionTest.java b/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/conditionalonbean/test/ConditionalOnBeanCompletionTest.java index ae2e8325b..2584af9e9 100644 --- a/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/conditionalonbean/test/ConditionalOnBeanCompletionTest.java +++ b/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/conditionalonbean/test/ConditionalOnBeanCompletionTest.java @@ -102,6 +102,11 @@ public class ConditionalOnBeanCompletionTest { assertCompletions("@ConditionalOnBean(type=ty<*>)", 2, "@ConditionalOnBean(type=\"org.example.type1\"<*>)"); } + @Test + public void testConditionalOnBeanCompletionWithoutQuotesWithComplexPrefixForTypeAttribute() throws Exception { + assertCompletions("@ConditionalOnBean(type=org.exam<*>)", 2, "@ConditionalOnBean(type=\"org.example.type1\"<*>)"); + } + @Test public void testConditionalOnBeanCompletionWithoutQuotesWithPrefixWithoutMatches() throws Exception { assertCompletions("@ConditionalOnBean(\"XXX<*>\")", 0, null); @@ -169,6 +174,20 @@ public class ConditionalOnBeanCompletionTest { assertCompletions("@ConditionalOnBean(name={\"bean1\",<*>\"bean2\"})", 1, "@ConditionalOnBean(name={\"bean1\",\"bean3\",<*>\"bean2\"})"); } + + @Test + public void testConditionalOnBeanTypeCompletions() throws Exception { + List completions = getCompletions("@ConditionalOnBean(type=<*>)"); + + assertEquals(2, completions.size()); + + CompletionItem completionItem = completions.get(0); + + completionItem = harness.resolveCompletionItem(completionItem); + assertEquals("type1", completionItem.getLabel()); + assertEquals("org.example.type1", completionItem.getDetail()); + assertEquals("org.example.type1", completionItem.getFilterText()); + } private void assertCompletions(String completionLine, int noOfExpectedCompletions, String expectedCompletedLine) throws Exception { String editorContent = """ @@ -215,4 +234,25 @@ public class ConditionalOnBeanCompletionTest { } } + private List getCompletions(String completionLine) throws Exception { + String editorContent = """ + package org.test; + + import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; + import org.springframework.context.annotation.Bean; + import org.springframework.context.annotation.Configuration; + + @Configuration + public class TestConditionalOnBeanCompletion { + """ + + completionLine + "\n" + + """ + @Bean + public void method() { + } + """; + + Editor editor = harness.newEditor(LanguageId.JAVA, editorContent, tempJavaDocUri); + return editor.getCompletions(); + } } \ No newline at end of file