From fe65fb9b5831f92fe6520b91078e66f04336fd16 Mon Sep 17 00:00:00 2001 From: Martin Lippert Date: Tue, 16 Apr 2019 10:48:37 +0200 Subject: [PATCH] early steps towards content-assist for bean references in Spring XML config files --- .../app/BootLanguageServerInitializer.java | 2 +- .../beans/BeansSymbolAddOnInformation.java | 30 ++++++ .../boot/java/beans/BeansSymbolProvider.java | 6 +- .../java/beans/ComponentSymbolProvider.java | 6 +- .../data/DataRepositorySymbolProvider.java | 7 +- ...SpringIndexerXMLNamespaceHandlerBeans.java | 5 +- .../boot/xml/SpringXMLCompletionEngine.java | 16 ++- .../SpringXMLLanguageServerComponents.java | 7 +- .../BeanRefCompletionProposalProvider.java | 97 +++++++++++++++++++ .../beans/test/SpringIndexerBeansTest.java | 21 +++- .../test/SpringIndexerFunctionBeansTest.java | 20 +++- .../DataRepositorySymbolProviderTest.java | 9 +- .../test/SpringIndexerXMLProjectTest.java | 30 ++++++ 13 files changed, 241 insertions(+), 15 deletions(-) create mode 100644 headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/beans/BeansSymbolAddOnInformation.java create mode 100644 headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/xml/completions/BeanRefCompletionProposalProvider.java diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/app/BootLanguageServerInitializer.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/app/BootLanguageServerInitializer.java index 1842aa787..576258244 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/app/BootLanguageServerInitializer.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/app/BootLanguageServerInitializer.java @@ -79,7 +79,7 @@ public class BootLanguageServerInitializer implements InitializingBean { CompositeLanguageServerComponents.Builder builder = new CompositeLanguageServerComponents.Builder(); builder.add(new BootPropertiesLanguageServerComponents(server, params, javaElementLocationProvider, parser, yamlStructureProvider, yamlAssistContextProvider, sourceLinks)); builder.add(new BootJavaLanguageServerComponents(server, params, sourceLinks, cuCache, adHocProperties, symbolCache, config, springIndexer, runningAppProvider)); - builder.add(new SpringXMLLanguageServerComponents(server, params)); + builder.add(new SpringXMLLanguageServerComponents(server, springIndexer, params)); components = builder.build(server); params.projectObserver.addListener(reconcileOpenDocuments(server, components)); diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/beans/BeansSymbolAddOnInformation.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/beans/BeansSymbolAddOnInformation.java new file mode 100644 index 000000000..7c15d2dbc --- /dev/null +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/beans/BeansSymbolAddOnInformation.java @@ -0,0 +1,30 @@ +/******************************************************************************* + * Copyright (c) 2019 Pivotal, Inc. + * 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: + * Pivotal, Inc. - initial API and implementation + *******************************************************************************/ +package org.springframework.ide.vscode.boot.java.beans; + +import org.springframework.ide.vscode.boot.java.handlers.SymbolAddOnInformation; + +/** + * @author Martin Lippert + */ +public class BeansSymbolAddOnInformation implements SymbolAddOnInformation { + + private final String beanID; + + public BeansSymbolAddOnInformation(String beanID) { + this.beanID = beanID; + } + + public String getBeanID() { + return beanID; + } + +} diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/beans/BeansSymbolProvider.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/beans/BeansSymbolProvider.java index 2d31b911c..4f518ad8c 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/beans/BeansSymbolProvider.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/beans/BeansSymbolProvider.java @@ -29,6 +29,7 @@ import org.eclipse.lsp4j.SymbolKind; import org.springframework.ide.vscode.boot.java.Annotations; import org.springframework.ide.vscode.boot.java.handlers.AbstractSymbolProvider; import org.springframework.ide.vscode.boot.java.handlers.EnhancedSymbolInformation; +import org.springframework.ide.vscode.boot.java.handlers.SymbolAddOnInformation; import org.springframework.ide.vscode.boot.java.utils.ASTUtils; import org.springframework.ide.vscode.boot.java.utils.CachedSymbol; import org.springframework.ide.vscode.boot.java.utils.FunctionUtils; @@ -66,7 +67,7 @@ public class BeansSymbolProvider extends AbstractSymbolProvider { beanLabel(isFunction, nameAndRegion.getT1(), beanType, "@Bean" + markerString), SymbolKind.Interface, new Location(doc.getUri(), doc.toRange(nameAndRegion.getT2()))), - null + new SymbolAddOnInformation[] {new BeansSymbolAddOnInformation(nameAndRegion.getT1())} ); context.getGeneratedSymbols().add(new CachedSymbol(context.getDocURI(), context.getLastModified(), enhancedSymbol)); @@ -88,7 +89,8 @@ public class BeansSymbolProvider extends AbstractSymbolProvider { SymbolKind.Interface, new Location(doc.getUri(), doc.toRange(functionBean.getT3()))); - context.getGeneratedSymbols().add(new CachedSymbol(context.getDocURI(), context.getLastModified(), new EnhancedSymbolInformation(symbol, null))); + context.getGeneratedSymbols().add(new CachedSymbol(context.getDocURI(), context.getLastModified(), + new EnhancedSymbolInformation(symbol, new SymbolAddOnInformation[] {new BeansSymbolAddOnInformation(functionBean.getT1())}))); } catch (BadLocationException e) { Log.log(e); diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/beans/ComponentSymbolProvider.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/beans/ComponentSymbolProvider.java index b5386043f..14f2c3299 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/beans/ComponentSymbolProvider.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/beans/ComponentSymbolProvider.java @@ -22,6 +22,7 @@ import org.eclipse.lsp4j.SymbolInformation; import org.eclipse.lsp4j.SymbolKind; import org.springframework.ide.vscode.boot.java.handlers.AbstractSymbolProvider; import org.springframework.ide.vscode.boot.java.handlers.EnhancedSymbolInformation; +import org.springframework.ide.vscode.boot.java.handlers.SymbolAddOnInformation; import org.springframework.ide.vscode.boot.java.utils.CachedSymbol; import org.springframework.ide.vscode.boot.java.utils.SpringIndexerJavaContext; import org.springframework.ide.vscode.commons.util.BadLocationException; @@ -56,7 +57,10 @@ public class ComponentSymbolProvider extends AbstractSymbolProvider { SymbolInformation symbol = new SymbolInformation( beanLabel("+", annotationTypeName, metaAnnotationNames, beanName, beanType), SymbolKind.Interface, new Location(doc.getUri(), doc.toRange(node.getStartPosition(), node.getLength()))); - return new EnhancedSymbolInformation(symbol, null); + + SymbolAddOnInformation[] addon = new SymbolAddOnInformation[] {new BeansSymbolAddOnInformation(beanName)}; + + return new EnhancedSymbolInformation(symbol, addon); } protected String beanLabel(String searchPrefix, String annotationTypeName, Collection metaAnnotationNames, String beanName, String beanType) { diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/data/DataRepositorySymbolProvider.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/data/DataRepositorySymbolProvider.java index 898e6bdee..712eb6ae6 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/data/DataRepositorySymbolProvider.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/data/DataRepositorySymbolProvider.java @@ -18,8 +18,10 @@ import org.eclipse.lsp4j.SymbolKind; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.ide.vscode.boot.java.beans.BeanUtils; +import org.springframework.ide.vscode.boot.java.beans.BeansSymbolAddOnInformation; import org.springframework.ide.vscode.boot.java.handlers.AbstractSymbolProvider; import org.springframework.ide.vscode.boot.java.handlers.EnhancedSymbolInformation; +import org.springframework.ide.vscode.boot.java.handlers.SymbolAddOnInformation; import org.springframework.ide.vscode.boot.java.utils.ASTUtils; import org.springframework.ide.vscode.boot.java.utils.CachedSymbol; import org.springframework.ide.vscode.boot.java.utils.SpringIndexerJavaContext; @@ -47,7 +49,10 @@ public class DataRepositorySymbolProvider extends AbstractSymbolProvider { beanLabel(true, repositoryBean.getT1(), repositoryBean.getT2(), repositoryBean.getT3()), SymbolKind.Interface, new Location(doc.getUri(), doc.toRange(repositoryBean.getT4()))); - EnhancedSymbolInformation enhancedSymbol = new EnhancedSymbolInformation(symbol, null); + + SymbolAddOnInformation[] addon = new SymbolAddOnInformation[] {new BeansSymbolAddOnInformation(repositoryBean.getT1())}; + EnhancedSymbolInformation enhancedSymbol = new EnhancedSymbolInformation(symbol, addon); + context.getGeneratedSymbols().add(new CachedSymbol(context.getDocURI(), context.getLastModified(), enhancedSymbol)); } catch (BadLocationException e) { log.error("error creating data repository symbol for a specific range", e); diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/SpringIndexerXMLNamespaceHandlerBeans.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/SpringIndexerXMLNamespaceHandlerBeans.java index 7b40012f3..0ba65c3f8 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/SpringIndexerXMLNamespaceHandlerBeans.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/SpringIndexerXMLNamespaceHandlerBeans.java @@ -20,7 +20,9 @@ import org.eclipse.lsp4j.SymbolKind; import org.eclipse.lsp4xml.dom.DOMAttr; import org.eclipse.lsp4xml.dom.DOMNode; import org.springframework.ide.vscode.boot.java.beans.BeanUtils; +import org.springframework.ide.vscode.boot.java.beans.BeansSymbolAddOnInformation; import org.springframework.ide.vscode.boot.java.handlers.EnhancedSymbolInformation; +import org.springframework.ide.vscode.boot.java.handlers.SymbolAddOnInformation; import org.springframework.ide.vscode.commons.java.IJavaProject; import org.springframework.ide.vscode.commons.util.text.TextDocument; import org.springframework.lang.NonNull; @@ -86,8 +88,9 @@ public class SpringIndexerXMLNamespaceHandlerBeans implements SpringIndexerXMLNa } SymbolInformation symbol = new SymbolInformation("@+ '" + beanID + "' " + beanClass, SymbolKind.Interface, new Location(docURI, range)); + SymbolAddOnInformation[] addon = new SymbolAddOnInformation[] {new BeansSymbolAddOnInformation(beanID)}; - EnhancedSymbolInformation fullSymbol = new EnhancedSymbolInformation(symbol, null); + EnhancedSymbolInformation fullSymbol = new EnhancedSymbolInformation(symbol, addon); CachedSymbol cachedSymbol = new CachedSymbol(docURI, lastModified, fullSymbol); generatedSymbols.add(cachedSymbol); diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/xml/SpringXMLCompletionEngine.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/xml/SpringXMLCompletionEngine.java index 4c01c7cb5..1e289928a 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/xml/SpringXMLCompletionEngine.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/xml/SpringXMLCompletionEngine.java @@ -22,6 +22,8 @@ import org.eclipse.lsp4xml.dom.DOMParser; import org.eclipse.lsp4xml.dom.parser.Scanner; import org.eclipse.lsp4xml.dom.parser.TokenType; import org.eclipse.lsp4xml.dom.parser.XMLScanner; +import org.springframework.ide.vscode.boot.app.SpringSymbolIndex; +import org.springframework.ide.vscode.boot.xml.completions.BeanRefCompletionProposalProvider; import org.springframework.ide.vscode.boot.xml.completions.PropertyNameCompletionProposalProvider; import org.springframework.ide.vscode.boot.xml.completions.TypeCompletionProposalProvider; import org.springframework.ide.vscode.commons.languageserver.completion.ICompletionEngine; @@ -37,17 +39,21 @@ public class SpringXMLCompletionEngine implements ICompletionEngine { private static final String BEANS_NAMESPACE = "http://www.springframework.org/schema/beans"; private static final String BEAN_ELEMENT = "bean"; - private static final String BEAN_CLASS_ATTRIBUTE = "class"; + private static final String CLASS_ATTRIBUTE = "class"; private static final String PROPERTY_ELEMENT = "property"; - private static final String PROPERTY_NAME_ATTRIBUTE = "name"; + private static final String NAME_ATTRIBUTE = "name"; + private static final String REF_ATTRIBUTE = "ref"; private final Map completionProviders; - public SpringXMLCompletionEngine(SpringXMLLanguageServerComponents springXMLLanguageServerComponents, JavaProjectFinder projectFinder) { + public SpringXMLCompletionEngine(SpringXMLLanguageServerComponents springXMLLanguageServerComponents, + JavaProjectFinder projectFinder, SpringSymbolIndex symbolIndex) { + this.completionProviders = new HashMap<>(); - this.completionProviders.put(new XMLCompletionProviderKey(BEANS_NAMESPACE, null, BEAN_ELEMENT, BEAN_CLASS_ATTRIBUTE), new TypeCompletionProposalProvider(projectFinder, true)); - this.completionProviders.put(new XMLCompletionProviderKey(BEANS_NAMESPACE, BEAN_ELEMENT, PROPERTY_ELEMENT, PROPERTY_NAME_ATTRIBUTE), new PropertyNameCompletionProposalProvider(projectFinder)); + this.completionProviders.put(new XMLCompletionProviderKey(BEANS_NAMESPACE, null, BEAN_ELEMENT, CLASS_ATTRIBUTE), new TypeCompletionProposalProvider(projectFinder, true)); + this.completionProviders.put(new XMLCompletionProviderKey(BEANS_NAMESPACE, BEAN_ELEMENT, PROPERTY_ELEMENT, NAME_ATTRIBUTE), new PropertyNameCompletionProposalProvider(projectFinder)); + this.completionProviders.put(new XMLCompletionProviderKey(BEANS_NAMESPACE, BEAN_ELEMENT, PROPERTY_ELEMENT, REF_ATTRIBUTE), new BeanRefCompletionProposalProvider(projectFinder, symbolIndex)); } @Override diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/xml/SpringXMLLanguageServerComponents.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/xml/SpringXMLLanguageServerComponents.java index f1b9c6589..e7850f88b 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/xml/SpringXMLLanguageServerComponents.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/xml/SpringXMLLanguageServerComponents.java @@ -15,6 +15,7 @@ import java.util.Set; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.ide.vscode.boot.app.BootLanguageServerParams; +import org.springframework.ide.vscode.boot.app.SpringSymbolIndex; import org.springframework.ide.vscode.commons.languageserver.completion.ICompletionEngine; import org.springframework.ide.vscode.commons.languageserver.composable.LanguageServerComponents; import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder; @@ -36,13 +37,17 @@ public class SpringXMLLanguageServerComponents implements LanguageServerComponen private final SimpleLanguageServer server; private final BootLanguageServerParams serverParams; private final JavaProjectFinder projectFinder; + private final SpringSymbolIndex symbolIndex; public SpringXMLLanguageServerComponents( SimpleLanguageServer server, + SpringSymbolIndex springIndexer, BootLanguageServerParams serverParams) { + this.server = server; this.serverParams = serverParams; this.projectFinder = serverParams.projectFinder; + this.symbolIndex = springIndexer; server.doOnInitialized(this::initialized); server.onShutdown(this::shutdown); @@ -55,7 +60,7 @@ public class SpringXMLLanguageServerComponents implements LanguageServerComponen @Override public ICompletionEngine getCompletionEngine() { - return new SpringXMLCompletionEngine(this, projectFinder); + return new SpringXMLCompletionEngine(this, projectFinder, symbolIndex); } @Override diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/xml/completions/BeanRefCompletionProposalProvider.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/xml/completions/BeanRefCompletionProposalProvider.java new file mode 100644 index 000000000..194be8671 --- /dev/null +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/xml/completions/BeanRefCompletionProposalProvider.java @@ -0,0 +1,97 @@ +/******************************************************************************* + * Copyright (c) 2019 Pivotal, Inc. + * 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: + * Pivotal, Inc. - initial API and implementation + *******************************************************************************/ +package org.springframework.ide.vscode.boot.xml.completions; + +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +import org.eclipse.lsp4j.CompletionItemKind; +import org.eclipse.lsp4xml.dom.DOMAttr; +import org.eclipse.lsp4xml.dom.DOMNode; +import org.eclipse.lsp4xml.dom.parser.Scanner; +import org.springframework.ide.vscode.boot.app.SpringSymbolIndex; +import org.springframework.ide.vscode.boot.java.beans.BeansSymbolAddOnInformation; +import org.springframework.ide.vscode.boot.java.handlers.SymbolAddOnInformation; +import org.springframework.ide.vscode.boot.xml.XMLCompletionProvider; +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.FuzzyMatcher; +import org.springframework.ide.vscode.commons.util.Renderable; +import org.springframework.ide.vscode.commons.util.text.TextDocument; + +import reactor.util.function.Tuple2; +import reactor.util.function.TupleExtensionsKt; +import reactor.util.function.Tuples; + +/** + * @author Martin Lippert + */ +public class BeanRefCompletionProposalProvider implements XMLCompletionProvider { + + private final JavaProjectFinder projectFinder; + private final SpringSymbolIndex symbolIndex; + + public BeanRefCompletionProposalProvider(JavaProjectFinder projectFinder, SpringSymbolIndex symbolIndex) { + this.projectFinder = projectFinder; + this.symbolIndex = symbolIndex; + } + + @Override + public Collection getCompletions(TextDocument doc, String namespace, DOMNode node, DOMAttr attributeAt, + Scanner scanner, int offset) { + + int tokenOffset = scanner.getTokenOffset(); + int tokenEnd = scanner.getTokenEnd(); + String tokenText = scanner.getTokenText(); + + Optional foundProject = this.projectFinder.find(doc.getId()); + if (foundProject.isPresent()) { + IJavaProject project = foundProject.get(); + + String prefix = tokenText.substring(0, offset - tokenOffset); + if (prefix.startsWith("\"")) { + prefix = prefix.substring(1); + } + + final String searchPrefix = prefix; + + List addonInfos = symbolIndex.getAllAdditionalInformation(addonInfo -> addonInfo instanceof BeansSymbolAddOnInformation); + + return addonInfos.stream() + .map(info -> (BeansSymbolAddOnInformation) info) + .map(beanInfo -> beanInfo.getBeanID()) + .filter(beanID -> beanID != null && beanID.length() > 0) + .map(beanID -> Tuples.of(beanID, FuzzyMatcher.matchScore(searchPrefix, beanID))) + .filter(tuple -> tuple.getT2() != 0.0) + .map(tuple -> createProposal(tuple.getT1(), doc, offset, tokenOffset, tokenEnd, tuple.getT2())) + .collect(Collectors.toList()); + }; + + return Collections.emptyList(); + } + + private ICompletionProposal createProposal(String beanID, TextDocument doc, int offset, int tokenStart, int tokenEnd, Double score) { + CompletionItemKind kind = CompletionItemKind.Reference; + + DocumentEdits edits = new DocumentEdits(doc); + edits.replace(tokenStart, tokenEnd, "\"" + beanID + "\""); + + Renderable renderable = null; + + return new TypeCompletionProposal(beanID, kind, edits, beanID, renderable, score); + } + +} diff --git a/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/beans/test/SpringIndexerBeansTest.java b/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/beans/test/SpringIndexerBeansTest.java index 0424f68bb..59676874b 100644 --- a/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/beans/test/SpringIndexerBeansTest.java +++ b/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/beans/test/SpringIndexerBeansTest.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2017, 2018 Pivotal, Inc. + * Copyright (c) 2017, 2019 Pivotal, Inc. * 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 @@ -10,9 +10,13 @@ *******************************************************************************/ package org.springframework.ide.vscode.boot.java.beans.test; +import static org.junit.Assert.assertEquals; + import java.io.File; +import java.util.List; import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; import org.eclipse.lsp4j.TextDocumentIdentifier; import org.junit.Before; @@ -24,6 +28,8 @@ import org.springframework.ide.vscode.boot.app.BootLanguageServerInitializer; import org.springframework.ide.vscode.boot.app.SpringSymbolIndex; import org.springframework.ide.vscode.boot.bootiful.BootLanguageServerTest; import org.springframework.ide.vscode.boot.bootiful.SymbolProviderTestConf; +import org.springframework.ide.vscode.boot.java.beans.BeansSymbolAddOnInformation; +import org.springframework.ide.vscode.boot.java.handlers.SymbolAddOnInformation; import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder; import org.springframework.ide.vscode.project.harness.BootLanguageServerHarness; import org.springframework.ide.vscode.project.harness.ProjectsHarness; @@ -66,6 +72,19 @@ public class SpringIndexerBeansTest { SpringIndexerHarness.symbol("@Configuration", "@+ 'simpleConfiguration' (@Configuration <: @Component) SimpleConfiguration"), SpringIndexerHarness.symbol("@Bean", "@+ 'simpleBean' (@Bean) BeanClass") ); + + List addon = indexer.getAdditonalInformation(docUri); + assertEquals(2, addon.size()); + + assertEquals(1, addon.stream() + .filter(info -> info instanceof BeansSymbolAddOnInformation) + .filter(info -> "simpleConfiguration".equals(((BeansSymbolAddOnInformation)info).getBeanID())) + .count()); + + assertEquals(1, addon.stream() + .filter(info -> info instanceof BeansSymbolAddOnInformation) + .filter(info -> "simpleBean".equals(((BeansSymbolAddOnInformation)info).getBeanID())) + .count()); } @Test public void testScanSpecialConfigurationClass() throws Exception { diff --git a/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/beans/test/SpringIndexerFunctionBeansTest.java b/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/beans/test/SpringIndexerFunctionBeansTest.java index fc5a93cf4..1c260c1d9 100644 --- a/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/beans/test/SpringIndexerFunctionBeansTest.java +++ b/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/beans/test/SpringIndexerFunctionBeansTest.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2017, 2018 Pivotal, Inc. + * Copyright (c) 2017, 2019 Pivotal, Inc. * 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 @@ -10,7 +10,10 @@ *******************************************************************************/ package org.springframework.ide.vscode.boot.java.beans.test; +import static org.junit.Assert.assertEquals; + import java.io.File; +import java.util.List; import java.util.concurrent.CompletableFuture; import java.util.concurrent.TimeUnit; @@ -23,6 +26,8 @@ import org.springframework.context.annotation.Import; import org.springframework.ide.vscode.boot.app.SpringSymbolIndex; import org.springframework.ide.vscode.boot.bootiful.BootLanguageServerTest; import org.springframework.ide.vscode.boot.bootiful.SymbolProviderTestConf; +import org.springframework.ide.vscode.boot.java.beans.BeansSymbolAddOnInformation; +import org.springframework.ide.vscode.boot.java.handlers.SymbolAddOnInformation; import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder; import org.springframework.ide.vscode.project.harness.BootLanguageServerHarness; import org.springframework.ide.vscode.project.harness.ProjectsHarness; @@ -64,6 +69,19 @@ public class SpringIndexerFunctionBeansTest { SpringIndexerHarness.symbol("@Configuration", "@+ 'functionClass' (@Configuration <: @Component) FunctionClass"), SpringIndexerHarness.symbol("@Bean", "@> 'uppercase' (@Bean) Function") ); + + List addon = indexer.getAdditonalInformation(docUri); + assertEquals(2, addon.size()); + + assertEquals(1, addon.stream() + .filter(info -> info instanceof BeansSymbolAddOnInformation) + .filter(info -> "functionClass".equals(((BeansSymbolAddOnInformation)info).getBeanID())) + .count()); + + assertEquals(1, addon.stream() + .filter(info -> info instanceof BeansSymbolAddOnInformation) + .filter(info -> "uppercase".equals(((BeansSymbolAddOnInformation)info).getBeanID())) + .count()); } @Test diff --git a/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/data/test/DataRepositorySymbolProviderTest.java b/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/data/test/DataRepositorySymbolProviderTest.java index e6dbdc724..29bbe1a29 100644 --- a/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/data/test/DataRepositorySymbolProviderTest.java +++ b/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/data/test/DataRepositorySymbolProviderTest.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2018 Pivotal, Inc. + * Copyright (c) 2018, 2019 Pivotal, Inc. * 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 @@ -29,6 +29,8 @@ import org.springframework.context.annotation.Import; import org.springframework.ide.vscode.boot.app.SpringSymbolIndex; import org.springframework.ide.vscode.boot.bootiful.BootLanguageServerTest; import org.springframework.ide.vscode.boot.bootiful.SymbolProviderTestConf; +import org.springframework.ide.vscode.boot.java.beans.BeansSymbolAddOnInformation; +import org.springframework.ide.vscode.boot.java.handlers.SymbolAddOnInformation; import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder; import org.springframework.ide.vscode.project.harness.BootLanguageServerHarness; import org.springframework.ide.vscode.project.harness.ProjectsHarness; @@ -68,6 +70,11 @@ public class DataRepositorySymbolProviderTest { List symbols = indexer.getSymbols(docUri); assertEquals(1, symbols.size()); assertTrue(containsSymbol(symbols, "@+ 'customerRepository' (Customer) Repository", docUri, 6, 17, 6, 35)); + + List addon = indexer.getAdditonalInformation(docUri); + assertEquals(1, addon.size()); + + assertEquals("customerRepository", ((BeansSymbolAddOnInformation)addon.get(0)).getBeanID()); } private boolean containsSymbol(List symbols, String name, String uri, int startLine, int startCHaracter, int endLine, int endCharacter) { diff --git a/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/utils/test/SpringIndexerXMLProjectTest.java b/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/utils/test/SpringIndexerXMLProjectTest.java index a1d80e415..3ff718e69 100644 --- a/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/utils/test/SpringIndexerXMLProjectTest.java +++ b/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/utils/test/SpringIndexerXMLProjectTest.java @@ -29,6 +29,8 @@ import org.springframework.context.annotation.Import; import org.springframework.ide.vscode.boot.app.SpringSymbolIndex; import org.springframework.ide.vscode.boot.bootiful.BootLanguageServerTest; import org.springframework.ide.vscode.boot.bootiful.SymbolProviderTestConf; +import org.springframework.ide.vscode.boot.java.beans.BeansSymbolAddOnInformation; +import org.springframework.ide.vscode.boot.java.handlers.SymbolAddOnInformation; import org.springframework.ide.vscode.commons.java.IJavaProject; import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder; import org.springframework.ide.vscode.project.harness.BootLanguageServerHarness; @@ -78,8 +80,36 @@ public class SpringIndexerXMLProjectTest { assertTrue(containsSymbol(allSymbols, "@+ 'namedParameterJdbcTemplate' NamedParameterJdbcTemplate", docUri, 12, 14, 12, 45)); assertTrue(containsSymbol(allSymbols, "@+ 'persistenceExceptionTranslationPostProcessor' PersistenceExceptionTranslationPostProcessor", docUri, 18, 10, 18, 97)); + List addon = indexer.getAdditonalInformation(docUri); + assertEquals(4, addon.size()); + + assertEquals(1, addon.stream() + .filter(info -> info instanceof BeansSymbolAddOnInformation) + .filter(info -> "transactionManager".equals(((BeansSymbolAddOnInformation)info).getBeanID())) + .count()); + + assertEquals(1, addon.stream() + .filter(info -> info instanceof BeansSymbolAddOnInformation) + .filter(info -> "jdbcTemplate".equals(((BeansSymbolAddOnInformation)info).getBeanID())) + .count()); + + assertEquals(1, addon.stream() + .filter(info -> info instanceof BeansSymbolAddOnInformation) + .filter(info -> "namedParameterJdbcTemplate".equals(((BeansSymbolAddOnInformation)info).getBeanID())) + .count()); + + assertEquals(1, addon.stream() + .filter(info -> info instanceof BeansSymbolAddOnInformation) + .filter(info -> "persistenceExceptionTranslationPostProcessor".equals(((BeansSymbolAddOnInformation)info).getBeanID())) + .count()); + + String beansOnClasspathDocUri = directory.toPath().resolve("src/main/resources/beans.xml").toUri().toString(); assertTrue(containsSymbol(allSymbols, "@+ 'sb' SimpleBean", beansOnClasspathDocUri, 6, 14, 6, 21)); + + addon = indexer.getAdditonalInformation(beansOnClasspathDocUri); + assertEquals(1, addon.size()); + assertEquals("sb", ((BeansSymbolAddOnInformation)addon.get(0)).getBeanID()); } private boolean containsSymbol(List symbols, String name, String uri, int startLine, int startCHaracter, int endLine, int endCharacter) {