From 4aeaf05a4f51521869638b15d9fba9ea1c9d31f2 Mon Sep 17 00:00:00 2001 From: Martin Lippert Date: Thu, 24 Oct 2024 22:57:21 +0200 Subject: [PATCH] refactored annotation attribute completion proecessors to allow more specific proposals to be created --- ...nnotationAttributeCompletionProcessor.java | 22 +++---- ...AnnotationAttributeCompletionProposal.java | 17 +++--- ...AnnotationAttributeCompletionProvider.java | 4 +- .../AnnotationAttributeProposal.java | 50 +++++++++++++++ .../beans/BeanNamesCompletionProcessor.java | 9 +-- .../beans/BeanTypesCompletionProcessor.java | 15 ++--- .../beans/DependsOnCompletionProcessor.java | 9 +-- .../java/beans/NamedCompletionProvider.java | 9 +-- .../java/beans/ProfileCompletionProvider.java | 9 +-- .../beans/QualifierCompletionProvider.java | 8 +-- .../beans/ResourceCompletionProvider.java | 9 +-- ...ditionalOnResourceCompletionProcessor.java | 13 ++-- .../ContextConfigurationProcessor.java | 21 +++---- .../CronExpressionCompletionProvider.java | 61 +++++++++---------- .../java/scope/ScopeCompletionProcessor.java | 26 ++++---- .../java/value/ValueCompletionProcessor.java | 5 +- .../test/ConditionalOnBeanCompletionTest.java | 18 +++--- 17 files changed, 177 insertions(+), 128 deletions(-) create mode 100644 headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/annotations/AnnotationAttributeProposal.java 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 c020c7700..5cf52f94c 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 @@ -12,7 +12,6 @@ package org.springframework.ide.vscode.boot.java.annotations; import java.util.Collection; import java.util.HashSet; -import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Optional; @@ -134,21 +133,22 @@ public class AnnotationAttributeCompletionProcessor implements CompletionProvide AnnotationAttributeCompletionProvider completionProvider = this.completionProviders.get(attributeName); if (completionProvider != null) { - Map proposals = completionProvider.getCompletionCandidates(project, node); - Map filteredProposals = proposals.entrySet().stream() - .filter(candidate -> candidate.getKey().toLowerCase().contains(filterPrefix.toLowerCase())) - .filter(candidate -> !alreadyMentionedValues.contains(candidate.getKey())) - .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue, (u, v) -> u, LinkedHashMap::new)); + List proposals = completionProvider.getCompletionCandidates(project, node); + + List filteredProposals = proposals.stream() + .filter(proposal -> proposal.getLabel().toLowerCase().contains(filterPrefix.toLowerCase())) + .filter(proposal -> !alreadyMentionedValues.contains(proposal.getLabel())) + .collect(Collectors.toList()); + double score = filteredProposals.size(); - for (Map.Entry entry : filteredProposals.entrySet()) { - String candidate = entry.getKey(); + for (AnnotationAttributeProposal candidate : filteredProposals) { DocumentEdits edits = new DocumentEdits(doc, false); - edits.replace(startOffset, endOffset, createReplacementText.apply(candidate)); + edits.replace(startOffset, endOffset, createReplacementText.apply(candidate.getLabel())); AnnotationAttributeCompletionProposal proposal = new AnnotationAttributeCompletionProposal(edits, - candidate, entry.getValue(), null, score--); - completions.add(proposal); + candidate, null, score--); + completions.add(proposal); } } } 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 de8b0b701..88c6ca325 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 @@ -20,25 +20,26 @@ import org.springframework.ide.vscode.commons.util.Renderable; */ public class AnnotationAttributeCompletionProposal extends ScoreableProposal { - private static final String EMPTY_DETAIL = ""; + private final AnnotationAttributeProposal coreProposal; private final DocumentEdits edits; - private final String label; - private final String detail; private final Renderable documentation; private final double score; - public AnnotationAttributeCompletionProposal(DocumentEdits edits, String label, String detail, Renderable documentation, double score) { + public AnnotationAttributeCompletionProposal(DocumentEdits edits, AnnotationAttributeProposal coreProposal, Renderable documentation, double score) { this.edits = edits; - this.label = label; - this.detail = detail == null ? EMPTY_DETAIL : detail; + this.coreProposal = coreProposal; this.documentation = documentation; 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.label; + return this.coreProposal.getLabel(); } @Override @@ -53,7 +54,7 @@ public class AnnotationAttributeCompletionProposal extends ScoreableProposal { @Override public String getDetail() { - return this.detail; + return this.coreProposal.getDetail(); } @Override diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/annotations/AnnotationAttributeCompletionProvider.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/annotations/AnnotationAttributeCompletionProvider.java index 735ed6b52..b4292b0ab 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/annotations/AnnotationAttributeCompletionProvider.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/annotations/AnnotationAttributeCompletionProvider.java @@ -10,13 +10,13 @@ *******************************************************************************/ package org.springframework.ide.vscode.boot.java.annotations; -import java.util.Map; +import java.util.List; import org.eclipse.jdt.core.dom.ASTNode; import org.springframework.ide.vscode.commons.java.IJavaProject; public interface AnnotationAttributeCompletionProvider { - Map getCompletionCandidates(IJavaProject project, ASTNode node); + List getCompletionCandidates(IJavaProject project, ASTNode node); } 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 new file mode 100644 index 000000000..0eb42c0b2 --- /dev/null +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/annotations/AnnotationAttributeProposal.java @@ -0,0 +1,50 @@ +/******************************************************************************* + * Copyright (c) 2024 Broadcom + * 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 + * https://www.eclipse.org/legal/epl-v10.html + * + * Contributors: + * Broadcom - initial API and implementation + *******************************************************************************/ +package org.springframework.ide.vscode.boot.java.annotations; + +/** + * @author Martin Lippert + */ +public class AnnotationAttributeProposal { + + private static final String EMPTY_DETAIL = ""; + + private final String filterText; + private final String label; + private final String detail; + + public AnnotationAttributeProposal(String label) { + this(label, label, label); + } + + public AnnotationAttributeProposal(String label, String detail) { + this(label, detail, label); + } + + public AnnotationAttributeProposal(String label, String detail, String filterText) { + this.label = label; + this.detail = detail == null ? EMPTY_DETAIL : detail; + this.filterText = filterText; + } + + public String getLabel() { + return label; + } + + public String getDetail() { + return detail; + } + + public String getFilterText() { + return filterText; + } + +} diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/beans/BeanNamesCompletionProcessor.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/beans/BeanNamesCompletionProcessor.java index b0d640992..44eca70e4 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/beans/BeanNamesCompletionProcessor.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/beans/BeanNamesCompletionProcessor.java @@ -11,13 +11,13 @@ package org.springframework.ide.vscode.boot.java.beans; import java.util.Arrays; -import java.util.LinkedHashMap; -import java.util.Map; +import java.util.List; import java.util.stream.Collectors; import org.eclipse.jdt.core.dom.ASTNode; import org.springframework.ide.vscode.boot.index.SpringMetamodelIndex; import org.springframework.ide.vscode.boot.java.annotations.AnnotationAttributeCompletionProvider; +import org.springframework.ide.vscode.boot.java.annotations.AnnotationAttributeProposal; import org.springframework.ide.vscode.commons.java.IJavaProject; import org.springframework.ide.vscode.commons.protocol.spring.Bean; @@ -33,11 +33,12 @@ public class BeanNamesCompletionProcessor implements AnnotationAttributeCompleti } @Override - public Map getCompletionCandidates(IJavaProject project, ASTNode node) { + public List getCompletionCandidates(IJavaProject project, ASTNode node) { Bean[] beans = this.springIndex.getBeansOfProject(project.getElementName()); return Arrays.stream(beans) .map(Bean::getName) .distinct() - .collect(Collectors.toMap(key -> key, value -> value, (u, v) -> u, LinkedHashMap::new)); + .map(beanName -> new AnnotationAttributeProposal(beanName)) + .collect(Collectors.toList()); } } 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 dcdc6c18f..291d9307d 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 @@ -10,17 +10,17 @@ *******************************************************************************/ package org.springframework.ide.vscode.boot.java.beans; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + import org.eclipse.jdt.core.dom.ASTNode; import org.springframework.ide.vscode.boot.index.SpringMetamodelIndex; import org.springframework.ide.vscode.boot.java.annotations.AnnotationAttributeCompletionProvider; +import org.springframework.ide.vscode.boot.java.annotations.AnnotationAttributeProposal; import org.springframework.ide.vscode.commons.java.IJavaProject; import org.springframework.ide.vscode.commons.protocol.spring.Bean; -import java.util.Arrays; -import java.util.LinkedHashMap; -import java.util.Map; -import java.util.stream.Collectors; - /** * @author Karthik Sankaranarayanan */ @@ -33,11 +33,12 @@ public class BeanTypesCompletionProcessor implements AnnotationAttributeCompleti } @Override - public Map getCompletionCandidates(IJavaProject project, ASTNode node) { + public List getCompletionCandidates(IJavaProject project, ASTNode node) { Bean[] beans = this.springIndex.getBeansOfProject(project.getElementName()); return Arrays.stream(beans) .map(Bean::getType) .distinct() - .collect(Collectors.toMap(key -> key, value -> value, (u, v) -> u, LinkedHashMap::new)); + .map(beanType -> new AnnotationAttributeProposal(beanType)) + .collect(Collectors.toList()); } } diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/beans/DependsOnCompletionProcessor.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/beans/DependsOnCompletionProcessor.java index 551f12865..a86633db0 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/beans/DependsOnCompletionProcessor.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/beans/DependsOnCompletionProcessor.java @@ -11,13 +11,13 @@ package org.springframework.ide.vscode.boot.java.beans; import java.util.Arrays; -import java.util.LinkedHashMap; -import java.util.Map; +import java.util.List; import java.util.stream.Collectors; import org.eclipse.jdt.core.dom.ASTNode; import org.springframework.ide.vscode.boot.index.SpringMetamodelIndex; import org.springframework.ide.vscode.boot.java.annotations.AnnotationAttributeCompletionProvider; +import org.springframework.ide.vscode.boot.java.annotations.AnnotationAttributeProposal; import org.springframework.ide.vscode.commons.java.IJavaProject; /** @@ -238,11 +238,12 @@ public class DependsOnCompletionProcessor implements AnnotationAttributeCompleti // } @Override - public Map getCompletionCandidates(IJavaProject project, ASTNode node) { + public List getCompletionCandidates(IJavaProject project, ASTNode node) { return Arrays.stream(this.springIndex.getBeansOfProject(project.getElementName())) .map(bean -> bean.getName()) .distinct() - .collect(Collectors.toMap(key -> key, value -> value, (u, v) -> u, LinkedHashMap::new)); + .map(beanName -> new AnnotationAttributeProposal(beanName)) + .collect(Collectors.toList()); } diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/beans/NamedCompletionProvider.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/beans/NamedCompletionProvider.java index 9cee24c28..c42a8bf54 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/beans/NamedCompletionProvider.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/beans/NamedCompletionProvider.java @@ -11,8 +11,7 @@ package org.springframework.ide.vscode.boot.java.beans; import java.util.Arrays; -import java.util.LinkedHashMap; -import java.util.Map; +import java.util.List; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -20,6 +19,7 @@ import org.eclipse.jdt.core.dom.ASTNode; import org.springframework.ide.vscode.boot.index.SpringMetamodelIndex; import org.springframework.ide.vscode.boot.java.Annotations; import org.springframework.ide.vscode.boot.java.annotations.AnnotationAttributeCompletionProvider; +import org.springframework.ide.vscode.boot.java.annotations.AnnotationAttributeProposal; import org.springframework.ide.vscode.commons.java.IJavaProject; import org.springframework.ide.vscode.commons.protocol.spring.Bean; @@ -35,7 +35,7 @@ public class NamedCompletionProvider implements AnnotationAttributeCompletionPro } @Override - public Map getCompletionCandidates(IJavaProject project, ASTNode node) { + public List getCompletionCandidates(IJavaProject project, ASTNode node) { Bean[] beans = this.springIndex.getBeansOfProject(project.getElementName()); @@ -43,7 +43,8 @@ public class NamedCompletionProvider implements AnnotationAttributeCompletionPro findAllNamedValues(beans), Arrays.stream(beans).map(bean -> bean.getName())) .distinct() - .collect(Collectors.toMap(key -> key, value -> value, (u, v) -> u, LinkedHashMap::new)); + .map(beanName -> new AnnotationAttributeProposal(beanName)) + .collect(Collectors.toList()); } private Stream findAllNamedValues(Bean[] beans) { diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/beans/ProfileCompletionProvider.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/beans/ProfileCompletionProvider.java index 422a1236a..26a1ca92a 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/beans/ProfileCompletionProvider.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/beans/ProfileCompletionProvider.java @@ -11,8 +11,7 @@ package org.springframework.ide.vscode.boot.java.beans; import java.util.Arrays; -import java.util.LinkedHashMap; -import java.util.Map; +import java.util.List; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -20,6 +19,7 @@ import org.eclipse.jdt.core.dom.ASTNode; import org.springframework.ide.vscode.boot.index.SpringMetamodelIndex; import org.springframework.ide.vscode.boot.java.Annotations; import org.springframework.ide.vscode.boot.java.annotations.AnnotationAttributeCompletionProvider; +import org.springframework.ide.vscode.boot.java.annotations.AnnotationAttributeProposal; import org.springframework.ide.vscode.commons.java.IJavaProject; import org.springframework.ide.vscode.commons.protocol.spring.Bean; @@ -35,13 +35,14 @@ public class ProfileCompletionProvider implements AnnotationAttributeCompletionP } @Override - public Map getCompletionCandidates(IJavaProject project, ASTNode node) { + public List getCompletionCandidates(IJavaProject project, ASTNode node) { Bean[] beans = this.springIndex.getBeansOfProject(project.getElementName()); return findAllProfiles(beans) .distinct() - .collect(Collectors.toMap(key -> key, value -> value, (u, v) -> u, LinkedHashMap::new)); + .map(profile -> new AnnotationAttributeProposal(profile)) + .collect(Collectors.toList()); } private Stream findAllProfiles(Bean[] beans) { diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/beans/QualifierCompletionProvider.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/beans/QualifierCompletionProvider.java index 78da789e8..20d17017b 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/beans/QualifierCompletionProvider.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/beans/QualifierCompletionProvider.java @@ -11,9 +11,7 @@ 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; @@ -25,6 +23,7 @@ import org.eclipse.jdt.core.dom.TypeDeclaration; import org.springframework.ide.vscode.boot.index.SpringMetamodelIndex; import org.springframework.ide.vscode.boot.java.Annotations; import org.springframework.ide.vscode.boot.java.annotations.AnnotationAttributeCompletionProvider; +import org.springframework.ide.vscode.boot.java.annotations.AnnotationAttributeProposal; import org.springframework.ide.vscode.commons.java.IJavaProject; import org.springframework.ide.vscode.commons.protocol.spring.Bean; @@ -40,7 +39,7 @@ public class QualifierCompletionProvider implements AnnotationAttributeCompletio } @Override - public Map getCompletionCandidates(IJavaProject project, ASTNode node) { + public List getCompletionCandidates(IJavaProject project, ASTNode node) { Bean[] beans = this.springIndex.getBeansOfProject(project.getElementName()); @@ -54,7 +53,8 @@ public class QualifierCompletionProvider implements AnnotationAttributeCompletio return candidates .distinct() - .collect(Collectors.toMap(key -> key, value -> value, (u, v) -> u, LinkedHashMap::new)); + .map(qualifier -> new AnnotationAttributeProposal(qualifier)) + .collect(Collectors.toList()); } private Stream findAllQualifiers(Bean[] beans) { diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/beans/ResourceCompletionProvider.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/beans/ResourceCompletionProvider.java index 060574bda..f850bf44a 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/beans/ResourceCompletionProvider.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/beans/ResourceCompletionProvider.java @@ -11,13 +11,13 @@ package org.springframework.ide.vscode.boot.java.beans; import java.util.Arrays; -import java.util.LinkedHashMap; -import java.util.Map; +import java.util.List; import java.util.stream.Collectors; import org.eclipse.jdt.core.dom.ASTNode; import org.springframework.ide.vscode.boot.index.SpringMetamodelIndex; import org.springframework.ide.vscode.boot.java.annotations.AnnotationAttributeCompletionProvider; +import org.springframework.ide.vscode.boot.java.annotations.AnnotationAttributeProposal; import org.springframework.ide.vscode.commons.java.IJavaProject; import org.springframework.ide.vscode.commons.protocol.spring.Bean; @@ -33,13 +33,14 @@ public class ResourceCompletionProvider implements AnnotationAttributeCompletion } @Override - public Map getCompletionCandidates(IJavaProject project, ASTNode node) { + public List getCompletionCandidates(IJavaProject project, ASTNode node) { Bean[] beans = this.springIndex.getBeansOfProject(project.getElementName()); return Arrays.stream(beans).map(bean -> bean.getName()) .distinct() - .collect(Collectors.toMap(key -> key, value -> value, (u, v) -> u, LinkedHashMap::new)); + .map(beanName -> new AnnotationAttributeProposal(beanName)) + .collect(Collectors.toList()); } } diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/conditionalonresource/ConditionalOnResourceCompletionProcessor.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/conditionalonresource/ConditionalOnResourceCompletionProcessor.java index bf00e9aa3..389fa70b1 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/conditionalonresource/ConditionalOnResourceCompletionProcessor.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/conditionalonresource/ConditionalOnResourceCompletionProcessor.java @@ -12,12 +12,12 @@ package org.springframework.ide.vscode.boot.java.conditionalonresource; import java.nio.file.Paths; import java.util.Comparator; -import java.util.LinkedHashMap; -import java.util.Map; +import java.util.List; import java.util.stream.Collectors; import org.eclipse.jdt.core.dom.ASTNode; import org.springframework.ide.vscode.boot.java.annotations.AnnotationAttributeCompletionProvider; +import org.springframework.ide.vscode.boot.java.annotations.AnnotationAttributeProposal; import org.springframework.ide.vscode.commons.java.IClasspathUtil; import org.springframework.ide.vscode.commons.java.IJavaProject; @@ -26,8 +26,8 @@ import org.springframework.ide.vscode.commons.java.IJavaProject; */ public class ConditionalOnResourceCompletionProcessor implements AnnotationAttributeCompletionProvider { - private Map findResources(IJavaProject project) { - Map resources = IClasspathUtil.getClasspathResources(project.getClasspath()).stream() + private List findResources(IJavaProject project) { + List resources = IClasspathUtil.getClasspathResources(project.getClasspath()).stream() .distinct() .sorted(new Comparator() { @Override @@ -37,13 +37,14 @@ public class ConditionalOnResourceCompletionProcessor implements AnnotationAttri }) .map(r -> r.replaceAll("\\\\", "/")) .map(r -> "classpath:" + r) - .collect(Collectors.toMap(key -> key, value -> value, (u, v) -> u, LinkedHashMap::new)); + .map(resource -> new AnnotationAttributeProposal(resource)) + .collect(Collectors.toList()); return resources; } @Override - public Map getCompletionCandidates(IJavaProject project, ASTNode node) { + public List getCompletionCandidates(IJavaProject project, ASTNode node) { return findResources(project); } diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/contextconfiguration/ContextConfigurationProcessor.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/contextconfiguration/ContextConfigurationProcessor.java index 1266efc8e..eb8a3ff5f 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/contextconfiguration/ContextConfigurationProcessor.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/contextconfiguration/ContextConfigurationProcessor.java @@ -10,11 +10,12 @@ *******************************************************************************/ package org.springframework.ide.vscode.boot.java.contextconfiguration; -import static org.springframework.ide.vscode.commons.util.StringUtil.camelCaseToHyphens; - import java.nio.file.Paths; -import java.util.*; -import java.util.stream.Collectors; +import java.util.Arrays; +import java.util.Collection; +import java.util.Comparator; +import java.util.List; +import java.util.Optional; import org.eclipse.jdt.core.dom.ASTNode; import org.eclipse.jdt.core.dom.Annotation; @@ -23,24 +24,17 @@ import org.eclipse.jdt.core.dom.MemberValuePair; import org.eclipse.jdt.core.dom.QualifiedName; import org.eclipse.jdt.core.dom.SimpleName; import org.eclipse.jdt.core.dom.StringLiteral; -import org.eclipse.lsp4j.TextDocumentIdentifier; -import org.openrewrite.yaml.internal.grammar.JsonPathParser; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.ide.vscode.boot.java.annotations.AnnotationAttributeCompletionProposal; +import org.springframework.ide.vscode.boot.java.annotations.AnnotationAttributeProposal; import org.springframework.ide.vscode.boot.java.handlers.CompletionProvider; -import org.springframework.ide.vscode.boot.metadata.ProjectBasedPropertyIndexProvider; -import org.springframework.ide.vscode.boot.metadata.PropertyInfo; -import org.springframework.ide.vscode.boot.metadata.SpringPropertyIndexProvider; import org.springframework.ide.vscode.commons.java.IClasspathUtil; import org.springframework.ide.vscode.commons.java.IJavaProject; import org.springframework.ide.vscode.commons.languageserver.completion.DocumentEdits; import org.springframework.ide.vscode.commons.languageserver.completion.ICompletionProposal; import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder; import org.springframework.ide.vscode.commons.util.BadLocationException; -import org.springframework.ide.vscode.commons.util.FuzzyMap; -import org.springframework.ide.vscode.commons.util.FuzzyMap.Match; -import org.springframework.ide.vscode.commons.util.text.IDocument; import org.springframework.ide.vscode.commons.util.text.TextDocument; /** @@ -128,7 +122,8 @@ public class ContextConfigurationProcessor implements CompletionProvider { String label = "/" + resource; - ICompletionProposal proposal = new AnnotationAttributeCompletionProposal(edits, label, label, null, score--); + AnnotationAttributeProposal coreProposal = new AnnotationAttributeProposal(label); + ICompletionProposal proposal = new AnnotationAttributeCompletionProposal(edits, coreProposal, null, score--); completions.add(proposal); } diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/cron/CronExpressionCompletionProvider.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/cron/CronExpressionCompletionProvider.java index d8333dab2..88c9d9780 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/cron/CronExpressionCompletionProvider.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/cron/CronExpressionCompletionProvider.java @@ -10,47 +10,44 @@ *******************************************************************************/ package org.springframework.ide.vscode.boot.java.cron; -import java.util.LinkedHashMap; -import java.util.Map; +import java.util.List; import org.eclipse.jdt.core.dom.ASTNode; import org.springframework.ide.vscode.boot.java.annotations.AnnotationAttributeCompletionProvider; +import org.springframework.ide.vscode.boot.java.annotations.AnnotationAttributeProposal; import org.springframework.ide.vscode.commons.java.IJavaProject; public class CronExpressionCompletionProvider implements AnnotationAttributeCompletionProvider { - private static final Map CRON_EXPRESSIONS_MAP = new LinkedHashMap<>(); - - static { - CRON_EXPRESSIONS_MAP.put("0 0 * * * *", "every hour"); - CRON_EXPRESSIONS_MAP.put("0 0 * * * 1-5", "every hour every day between Monday and Friday"); - CRON_EXPRESSIONS_MAP.put("0 * * * * *", "every minute"); - CRON_EXPRESSIONS_MAP.put("0 */5 * * * *", "every 5 minutes"); - CRON_EXPRESSIONS_MAP.put("0 0 */6 * * *", "every 6 hours at minute 0"); - CRON_EXPRESSIONS_MAP.put("0 0 * * * SUN", "every hour at Sunday day"); - CRON_EXPRESSIONS_MAP.put("0 0 0 * * *", "at 00:00"); - CRON_EXPRESSIONS_MAP.put("0 0 0 * * SAT,SUN", "at 00:00 on Saturday and Sunday"); - CRON_EXPRESSIONS_MAP.put("0 0 0 * * 6,0", "at 00:00 at Saturday and Sunday days"); - CRON_EXPRESSIONS_MAP.put("0 0 0 1-7 * SUN", "at 00:00 every day between 1 and 7 at Sunday day"); - CRON_EXPRESSIONS_MAP.put("0 0 0 1 * *", "at 00:00 at 1 day"); - CRON_EXPRESSIONS_MAP.put("0 0 0 1 1 *", "at 00:00 at 1 day at January month"); - CRON_EXPRESSIONS_MAP.put("0 0 8-18 * * *", "every hour between 8 and 18"); - CRON_EXPRESSIONS_MAP.put("0 0 9 * * MON", "at 09:00 at Monday day"); - CRON_EXPRESSIONS_MAP.put("0 0 10 * * *", "at 10:00"); - CRON_EXPRESSIONS_MAP.put("0 30 9 * JAN MON", "at 09:30 at January month at Monday day"); - CRON_EXPRESSIONS_MAP.put("10 * * * * *", "every minute at second 10"); - CRON_EXPRESSIONS_MAP.put("0 0 8-10 * * *", "every hour between 8 and 10"); - CRON_EXPRESSIONS_MAP.put("0 0/30 8-10 * * *", "every 30 minutes every hour between 8 and 10"); - CRON_EXPRESSIONS_MAP.put("0 0 0 L * *", " at 00:00 last day of month"); - CRON_EXPRESSIONS_MAP.put("0 0 0 1W * *", "at 00:00 the nearest weekday to the 1 of the month"); - CRON_EXPRESSIONS_MAP.put("0 0 0 * * THUL", "at 00:00 last Thursday of every month"); - CRON_EXPRESSIONS_MAP.put("0 0 0 ? * 5#2", "at 00:00 Friday 2 of every month"); - CRON_EXPRESSIONS_MAP.put("0 0 0 ? * MON#1", "at 00:00 Monday 1 of every month"); - } - + private static final List CRON_EXPRESSIONS_MAP = List.of( + new AnnotationAttributeProposal("0 0 * * * *", "every hour"), + new AnnotationAttributeProposal("0 0 * * * 1-5", "every hour every day between Monday and Friday"), + new AnnotationAttributeProposal("0 * * * * *", "every minute"), + new AnnotationAttributeProposal("0 */5 * * * *", "every 5 minutes"), + new AnnotationAttributeProposal("0 0 */6 * * *", "every 6 hours at minute 0"), + new AnnotationAttributeProposal("0 0 * * * SUN", "every hour at Sunday day"), + new AnnotationAttributeProposal("0 0 0 * * *", "at 00:00"), + new AnnotationAttributeProposal("0 0 0 * * SAT,SUN", "at 00:00 on Saturday and Sunday"), + new AnnotationAttributeProposal("0 0 0 * * 6,0", "at 00:00 at Saturday and Sunday days"), + new AnnotationAttributeProposal("0 0 0 1-7 * SUN", "at 00:00 every day between 1 and 7 at Sunday day"), + new AnnotationAttributeProposal("0 0 0 1 * *", "at 00:00 at 1 day"), + new AnnotationAttributeProposal("0 0 0 1 1 *", "at 00:00 at 1 day at January month"), + new AnnotationAttributeProposal("0 0 8-18 * * *", "every hour between 8 and 18"), + new AnnotationAttributeProposal("0 0 9 * * MON", "at 09:00 at Monday day"), + new AnnotationAttributeProposal("0 0 10 * * *", "at 10:00"), + new AnnotationAttributeProposal("0 30 9 * JAN MON", "at 09:30 at January month at Monday day"), + new AnnotationAttributeProposal("10 * * * * *", "every minute at second 10"), + new AnnotationAttributeProposal("0 0 8-10 * * *", "every hour between 8 and 10"), + new AnnotationAttributeProposal("0 0/30 8-10 * * *", "every 30 minutes every hour between 8 and 10"), + new AnnotationAttributeProposal("0 0 0 L * *", " at 00:00 last day of month"), + new AnnotationAttributeProposal("0 0 0 1W * *", "at 00:00 the nearest weekday to the 1 of the month"), + new AnnotationAttributeProposal("0 0 0 * * THUL", "at 00:00 last Thursday of every month"), + new AnnotationAttributeProposal("0 0 0 ? * 5#2", "at 00:00 Friday 2 of every month"), + new AnnotationAttributeProposal("0 0 0 ? * MON#1", "at 00:00 Monday 1 of every month") + ); @Override - public Map getCompletionCandidates(IJavaProject project, ASTNode node) { + public List getCompletionCandidates(IJavaProject project, ASTNode node) { return CRON_EXPRESSIONS_MAP; } } diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/scope/ScopeCompletionProcessor.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/scope/ScopeCompletionProcessor.java index 11ba0c4ed..22d7df880 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/scope/ScopeCompletionProcessor.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/scope/ScopeCompletionProcessor.java @@ -10,11 +10,11 @@ *******************************************************************************/ package org.springframework.ide.vscode.boot.java.scope; -import java.util.LinkedHashMap; -import java.util.Map; +import java.util.List; import org.eclipse.jdt.core.dom.ASTNode; import org.springframework.ide.vscode.boot.java.annotations.AnnotationAttributeCompletionProvider; +import org.springframework.ide.vscode.boot.java.annotations.AnnotationAttributeProposal; import org.springframework.ide.vscode.commons.java.IJavaProject; /** @@ -22,20 +22,18 @@ import org.springframework.ide.vscode.commons.java.IJavaProject; */ public class ScopeCompletionProcessor implements AnnotationAttributeCompletionProvider { - private static final Map SCOPE_COMPLETIONS = new LinkedHashMap<>(); + private static final List SCOPE_COMPLETIONS = List.of( + new AnnotationAttributeProposal("application"), + new AnnotationAttributeProposal("globalSession"), + new AnnotationAttributeProposal("prototype"), + new AnnotationAttributeProposal("request"), + new AnnotationAttributeProposal("session"), + new AnnotationAttributeProposal("singleton"), + new AnnotationAttributeProposal("websocket") + ); - static { - SCOPE_COMPLETIONS.put("application", "application"); - SCOPE_COMPLETIONS.put("globalSession", "globalSession"); - SCOPE_COMPLETIONS.put("prototype", "prototype"); - SCOPE_COMPLETIONS.put("request", "request"); - SCOPE_COMPLETIONS.put("session", "session"); - SCOPE_COMPLETIONS.put("singleton", "singleton"); - SCOPE_COMPLETIONS.put("websocket", "websocket"); - } - @Override - public Map getCompletionCandidates(IJavaProject project, ASTNode node) { + public List getCompletionCandidates(IJavaProject project, ASTNode node) { return SCOPE_COMPLETIONS; } diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/value/ValueCompletionProcessor.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/value/ValueCompletionProcessor.java index a696ff416..56c2d4df7 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/value/ValueCompletionProcessor.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/value/ValueCompletionProcessor.java @@ -26,12 +26,12 @@ import org.eclipse.jdt.core.dom.ITypeBinding; import org.eclipse.jdt.core.dom.MemberValuePair; import org.eclipse.jdt.core.dom.Name; import org.eclipse.jdt.core.dom.QualifiedName; -import org.eclipse.jdt.core.dom.SimpleName; import org.eclipse.jdt.core.dom.StringLiteral; import org.eclipse.lsp4j.TextDocumentIdentifier; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.ide.vscode.boot.java.annotations.AnnotationAttributeCompletionProposal; +import org.springframework.ide.vscode.boot.java.annotations.AnnotationAttributeProposal; import org.springframework.ide.vscode.boot.java.handlers.CompletionProvider; import org.springframework.ide.vscode.boot.metadata.ProjectBasedPropertyIndexProvider; import org.springframework.ide.vscode.boot.metadata.PropertyInfo; @@ -270,7 +270,8 @@ public class ValueCompletionProcessor implements CompletionProvider { String label = "classpath:" + resource; - ICompletionProposal proposal = new AnnotationAttributeCompletionProposal(edits, label, label, null, score--); + AnnotationAttributeProposal coreProposal = new AnnotationAttributeProposal(label); + ICompletionProposal proposal = new AnnotationAttributeCompletionProposal(edits, coreProposal, null, score--); completions.add(proposal); } 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 aa1ebd8f1..ae2e8325b 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 @@ -76,8 +76,8 @@ public class ConditionalOnBeanCompletionTest { indexedBeans = springIndex.getBeansOfProject(project.getElementName()); tempJavaDocUri = directory.toPath().resolve("src/main/java/org/test/TempClass.java").toUri().toString(); - bean1 = new Bean("bean1", "type1", new Location(tempJavaDocUri, new Range(new Position(1,1), new Position(1, 20))), null, null, null); - bean2 = new Bean("bean2", "type2", new Location(tempJavaDocUri, new Range(new Position(1,1), new Position(1, 20))), null, null, null); + bean1 = new Bean("bean1", "org.example.type1", new Location(tempJavaDocUri, new Range(new Position(1,1), new Position(1, 20))), null, null, null); + bean2 = new Bean("bean2", "org.example.type2", new Location(tempJavaDocUri, new Range(new Position(1,1), new Position(1, 20))), null, null, null); springIndex.updateBeans(project.getElementName(), new Bean[] {bean1, bean2}); } @@ -89,7 +89,7 @@ public class ConditionalOnBeanCompletionTest { @Test public void testConditionalOnBeanCompletionWithoutQuotesWithoutPrefixWithTypeAttribute() throws Exception { - assertCompletions("@ConditionalOnBean(type=<*>)", 2, "@ConditionalOnBean(type=\"type1\"<*>)"); + assertCompletions("@ConditionalOnBean(type=<*>)", 2, "@ConditionalOnBean(type=\"org.example.type1\"<*>)"); } @Test @@ -99,7 +99,7 @@ public class ConditionalOnBeanCompletionTest { @Test public void testConditionalOnBeanCompletionWithoutQuotesWithPrefixWithTypeAttribute() throws Exception { - assertCompletions("@ConditionalOnBean(type=ty<*>)", 2, "@ConditionalOnBean(type=\"type1\"<*>)"); + assertCompletions("@ConditionalOnBean(type=ty<*>)", 2, "@ConditionalOnBean(type=\"org.example.type1\"<*>)"); } @Test @@ -119,7 +119,7 @@ public class ConditionalOnBeanCompletionTest { @Test public void testConditionalOnBeanCompletionWithoutQuotesWithAttributeTypeAndDefaultSpaces() throws Exception { - assertCompletions("@ConditionalOnBean(type = <*>)", 2, "@ConditionalOnBean(type = \"type1\"<*>)"); + assertCompletions("@ConditionalOnBean(type = <*>)", 2, "@ConditionalOnBean(type = \"org.example.type1\"<*>)"); } @Test @@ -139,7 +139,7 @@ public class ConditionalOnBeanCompletionTest { @Test public void testConditionalOnBeanCompletionWithoutQuotesWithTypeWithoutPrefixInsideArray() throws Exception { - assertCompletions("@ConditionalOnBean(type={<*>})", 2, "@ConditionalOnBean(type={\"type1\"<*>})"); + assertCompletions("@ConditionalOnBean(type={<*>})", 2, "@ConditionalOnBean(type={\"org.example.type1\"<*>})"); } @Test @@ -149,7 +149,7 @@ public class ConditionalOnBeanCompletionTest { @Test public void testConditionalOnBeanCompletionInsideOfArrayBehindExistingElementWithType() throws Exception { - assertCompletions("@ConditionalOnBean(type={\"type1\",<*>})", 1, "@ConditionalOnBean(type={\"type1\",\"type2\"<*>})"); + assertCompletions("@ConditionalOnBean(type={\"org.example.type1\",<*>})", 1, "@ConditionalOnBean(type={\"org.example.type1\",\"org.example.type2\"<*>})"); } @Test @@ -159,12 +159,12 @@ public class ConditionalOnBeanCompletionTest { @Test public void testConditionalOnBeanCompletionInsideOfArrayInFrontOfExistingElementWithType() throws Exception { - assertCompletions("@ConditionalOnBean(type={<*>\"type1\"})", 1, "@ConditionalOnBean(type={\"type2\",<*>\"type1\"})"); + assertCompletions("@ConditionalOnBean(type={<*>\"org.example.type1\"})", 1, "@ConditionalOnBean(type={\"org.example.type2\",<*>\"org.example.type1\"})"); } @Test public void testConditionalOnBeanCompletionInsideOfArrayBetweenExistingElements() throws Exception { - Bean bean3 = new Bean("bean3", "type3", new Location(tempJavaDocUri, new Range(new Position(1,1), new Position(1, 20))), null, null, null); + Bean bean3 = new Bean("bean3", "org.example.type3", new Location(tempJavaDocUri, new Range(new Position(1,1), new Position(1, 20))), null, null, null); springIndex.updateBeans(project.getElementName(), new Bean[] {bean1, bean2, bean3}); assertCompletions("@ConditionalOnBean(name={\"bean1\",<*>\"bean2\"})", 1, "@ConditionalOnBean(name={\"bean1\",\"bean3\",<*>\"bean2\"})");