Rework symbol provider inheritance to create fewer symbols with more info

This commit is contained in:
Kris De Volder
2017-11-20 15:10:49 -08:00
parent adc4d4f978
commit 733e59afd1
13 changed files with 150 additions and 186 deletions

View File

@@ -20,7 +20,7 @@ import org.eclipse.lsp4j.InitializeParams;
import org.eclipse.lsp4j.InitializeResult;
import org.eclipse.lsp4j.Registration;
import org.eclipse.lsp4j.RegistrationParams;
import org.springframework.ide.vscode.boot.java.annotations.AnnotationHierarchyAwareFactoryManager;
import org.springframework.ide.vscode.boot.java.annotations.AnnotationHierarchyAwareLookup;
import org.springframework.ide.vscode.boot.java.autowired.AutowiredHoverProvider;
import org.springframework.ide.vscode.boot.java.beans.BeansSymbolProvider;
import org.springframework.ide.vscode.boot.java.beans.ComponentSymbolProvider;
@@ -313,7 +313,7 @@ public class BootJavaLanguageServer extends SimpleLanguageServer {
}
protected SpringIndexer createAnnotationIndexer(SimpleLanguageServer server, JavaProjectFinder projectFinder) {
AnnotationHierarchyAwareFactoryManager<SymbolProvider> providers = new AnnotationHierarchyAwareFactoryManager<>();
AnnotationHierarchyAwareLookup<SymbolProvider> providers = new AnnotationHierarchyAwareLookup<>();
providers.put(Annotations.SPRING_REQUEST_MAPPING, new RequestMappingSymbolProvider());
providers.put(Annotations.SPRING_GET_MAPPING,
new RequestMappingSymbolProvider());
@@ -327,7 +327,7 @@ public class BootJavaLanguageServer extends SimpleLanguageServer {
new RequestMappingSymbolProvider());
providers.put(Annotations.BEAN, new BeansSymbolProvider());
providers.putFactory(Annotations.COMPONENT, ComponentSymbolProvider::new);
providers.put(Annotations.COMPONENT, new ComponentSymbolProvider());
return new SpringIndexer(this, projectFinder, providers);
}

View File

@@ -11,19 +11,23 @@
package org.springframework.ide.vscode.boot.java.annotations;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.function.Predicate;
import java.util.stream.Stream;
import org.eclipse.jdt.core.dom.Annotation;
import org.eclipse.jdt.core.dom.IAnnotationBinding;
import org.eclipse.jdt.core.dom.ITypeBinding;
import org.gradle.internal.io.SkipFirstTextStream;
import org.springframework.ide.vscode.commons.util.CollectorUtil;
import org.springframework.ide.vscode.commons.util.Log;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import com.google.common.collect.ImmutableList;
/**
@@ -67,11 +71,11 @@ public abstract class AnnotationHierarchies {
return seen;
}
public static Stream<String> findTransitiveSupers(ITypeBinding typeBinding, Set<String> seen) {
public static Stream<ITypeBinding> findTransitiveSupers(ITypeBinding typeBinding, Set<String> seen) {
String qname = typeBinding.getQualifiedName();
if (seen.add(qname)) {
return Stream.concat(
Stream.of(qname),
Stream.of(typeBinding),
getDirectSuperAnnotations(typeBinding).stream().flatMap(superBinding ->
findTransitiveSupers(superBinding, seen)
)
@@ -84,9 +88,22 @@ public abstract class AnnotationHierarchies {
ITypeBinding annotationType = annotation.resolveTypeBinding();
if (annotationType!=null) {
return findTransitiveSupers(annotationType, new HashSet<>())
.anyMatch(superType -> superType.equals(fqAnnotationTypeName));
.anyMatch(superType -> superType.getQualifiedName().equals(fqAnnotationTypeName));
}
return false;
}
public static Collection<ITypeBinding> getMetaAnnotations(ITypeBinding actualAnnotation, Predicate<String> isKeyAnnotationName) {
Stream<ITypeBinding> allSupers = findTransitiveSupers(actualAnnotation, new HashSet<>())
.skip(1); //Don't include 'actualAnnotation' itself.
return allSupers
.filter(candidate -> isMetaAnnotation(candidate, isKeyAnnotationName))
.collect(CollectorUtil.toImmutableList());
}
private static boolean isMetaAnnotation(ITypeBinding candidate, Predicate<String> isKeyAnnotationName) {
return findTransitiveSupers(candidate, new HashSet<>())
.anyMatch(sa -> isKeyAnnotationName.test(sa.getQualifiedName()));
}
}

View File

@@ -1,66 +0,0 @@
/*******************************************************************************
* Copyright (c) 2017 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
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* Pivotal, Inc. - initial API and implementation
*******************************************************************************/
package org.springframework.ide.vscode.boot.java.annotations;
import java.util.Collection;
import org.eclipse.jdt.core.dom.ITypeBinding;
import com.google.common.collect.ImmutableList;
import reactor.util.function.Tuple2;
/**
* @author Kris De Volder
*/
public class AnnotationHierarchyAwareFactoryManager<T> {
@FunctionalInterface
public interface Factory<T> {
T create(String fqAnnotationType);
}
private AnnotationHierarchyAwareLookup<Factory<T>> factories = new AnnotationHierarchyAwareLookup<Factory<T>>();
/**
* Deprecated, for proper handling of annotation inheritance, use putFactory method instead.
*/
@Deprecated
public void put(String fqAnnotationType, T value) {
factories.put(fqAnnotationType, true, (actualAnnotationType) ->
actualAnnotationType.equals(fqAnnotationType) ? value : null
);
}
/**
* Add a 'base' factory which creates a `T` for a given type of annotation.
* The factory will be passed the fq name of the annotation 'base' annotation.
* It is acceptable for the Factory to return null. Null values will simply
* be ignored.
*/
public void putFactory(String fqAnnotationType, Factory<T> factory) {
factories.put(fqAnnotationType, false, factory);
}
public Collection<T> get(ITypeBinding typeBinding) {
ImmutableList.Builder<T> builder = ImmutableList.builder();
for (Tuple2<String, Factory<T>> entry : factories.get(typeBinding)) {
String superAnnotationName = entry.getT1();
Factory<T> factory = entry.getT2();
T element = factory.create(superAnnotationName);
if (element!=null) {
builder.add(element);
}
}
return builder.build();
}
}

View File

@@ -13,13 +13,16 @@ package org.springframework.ide.vscode.boot.java.annotations;
import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.function.Consumer;
import org.eclipse.jdt.core.dom.ITypeBinding;
import org.springframework.ide.vscode.boot.java.requestmapping.RequestMappingSymbolProvider;
import org.springframework.ide.vscode.commons.util.Assert;
import org.springframework.ide.vscode.commons.util.StringUtil;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import reactor.util.function.Tuple2;
@@ -90,42 +93,35 @@ public class AnnotationHierarchyAwareLookup<T> {
* a symbol provider for Components should be asked to produce symbols for Component, Controller and RestController,
* so should result in 3 separate calls to the symbols provider.
*/
public Collection<Tuple2<String, T>> get(ITypeBinding annotationType) {
ImmutableSet.Builder<Tuple2<String, T>> associations = ImmutableSet.builder();
findElements(annotationType, new HashSet<>(), associations::add);
return associations.build();
public Collection<T> get(ITypeBinding annotationType) {
ImmutableList.Builder<T> found = ImmutableList.builder();
findElements(annotationType, new LinkedHashSet<>(), found::add);
return found.build();
}
private void findElements(ITypeBinding typeBinding, HashSet<String> seen, Consumer<Tuple2<String, T>> requestor) {
//Note: the 'seen' hashset is unneceassary if meta annotations do not annotate eachother
//in such a way as to create a cycle. Intuitively, you might expect that inheritance graphs
//do not contain cycles, but since these annotations can be coming from anywhere on
//a random project's classpath, we don't really know this for sure, so we must play it safe
//and guard the lookup against infinite looping.
private void findElements(ITypeBinding typeBinding, HashSet<String> seen, Consumer<T> requestor) {
String qname = typeBinding.getQualifiedName();
// int debugIndent = debug_in("findElements "+StringUtil.simpleName(qname));
// Consumer<Tuple2<String, T>> requestor = (e) -> {
// debug(debugIndent, "<== "+StringUtil.simpleName(e.getT1())+" from "+StringUtil.simpleName(qname));
// _requestor.accept(e);
// };
if (seen.add(qname)) {
Binding<T> binding = bindings.get(qname);
boolean isOverriding = false;
if (binding!=null) {
requestor.accept(Tuples.of(qname, binding.value));
requestor.accept(binding.value);
isOverriding = binding.isOverriding;
}
if (!isOverriding) {
for (ITypeBinding superAnnotation : AnnotationHierarchies.getDirectSuperAnnotations(typeBinding)) {
findElements(superAnnotation, seen, superResult -> {
requestor.accept(superResult);
requestor.accept(Tuples.of(qname, superResult.getT2()));
});
findElements(superAnnotation, seen, requestor);
}
}
}
// debug_out("findElements "+qname);
}
public void put(String annotationName, T value) {
put(annotationName, true, value);
}
public boolean containsKey(String fqName) {
return bindings.containsKey(fqName);
}
// private static int indent = 0;

View File

@@ -0,0 +1,51 @@
///*******************************************************************************
// * Copyright (c) 2017 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
// * http://www.eclipse.org/legal/epl-v10.html
// *
// * Contributors:
// * Pivotal, Inc. - initial API and implementation
// *******************************************************************************/
//package org.springframework.ide.vscode.boot.java.annotations;
//
//import java.util.Collection;
//
//import org.eclipse.jdt.core.dom.ITypeBinding;
//import org.springframework.ide.vscode.boot.java.handlers.SymbolProvider;
//
//import com.google.common.collect.ImmutableList;
//
//import reactor.util.function.Tuple2;
//
///**
// * @author Kris De Volder
// */
//public class SymbolProviderLookup {
//
// @FunctionalInterface
// public interface Factory<T> {
// T create(String fqAnnotationType);
// }
//
// private AnnotationHierarchyAwareLookup<SymbolProvider> providers = new AnnotationHierarchyAwareLookup<>();
//
// public void put(String fqAnnotationType, SymbolProvider value) {
// providers.put(fqAnnotationType, true, value);
// }
//
// public Collection<SymbolProvider> get(ITypeBinding typeBinding) {
// ImmutableList.Builder<T> builder = ImmutableList.builder();
// for (Tuple2<String, Factory<T>> entry : factories.get(typeBinding)) {
// String superAnnotationName = entry.getT1();
// Factory<T> factory = entry.getT2();
// T element = factory.create(superAnnotationName);
// if (element!=null) {
// builder.add(element);
// }
// }
// return builder.build();
// }
//
//}

View File

@@ -89,7 +89,7 @@ public class BeansSymbolProvider implements SymbolProvider {
// }
@Override
public Collection<SymbolInformation> getSymbols(Annotation node, ITypeBinding annotationType, TextDocument doc) {
public Collection<SymbolInformation> getSymbols(Annotation node, ITypeBinding annotationType, Collection<ITypeBinding> metaAnnotations, TextDocument doc) {
boolean isFunction = isFunctionBean(node);
ImmutableList.Builder<SymbolInformation> symbols = ImmutableList.builder();
String beanType = getBeanType(node);

View File

@@ -11,6 +11,7 @@
package org.springframework.ide.vscode.boot.java.beans;
import java.util.Collection;
import java.util.stream.Collectors;
import org.eclipse.jdt.core.dom.ASTNode;
import org.eclipse.jdt.core.dom.Annotation;
@@ -33,23 +34,12 @@ import com.google.common.collect.ImmutableList;
*/
public class ComponentSymbolProvider implements SymbolProvider {
private String annotationName;
private String simpleAnnotationName;
public ComponentSymbolProvider(String annotationName) {
this.annotationName = annotationName;
this.simpleAnnotationName = StringUtil.simpleName(annotationName);
}
@Override
public Collection<SymbolInformation> getSymbols(Annotation node, ITypeBinding annotationType, TextDocument doc) {
public Collection<SymbolInformation> getSymbols(Annotation node, ITypeBinding annotationType, Collection<ITypeBinding> metaAnnotations, TextDocument doc) {
try {
ImmutableList.Builder<SymbolInformation> symbols = ImmutableList.builder();
symbols.add(createSymbol(node, doc, false));
if (isExactAnnotationType(annotationType)) {
symbols.add(createSymbol(node, doc, true));
}
return symbols.build();
return ImmutableList.of(
createSymbol(node, annotationType, metaAnnotations, doc)
);
}
catch (Exception e) {
Log.log(e);
@@ -57,24 +47,21 @@ public class ComponentSymbolProvider implements SymbolProvider {
return ImmutableList.of();
}
protected SymbolInformation createSymbol(Annotation node, TextDocument doc, boolean isExactAnnotationType) throws BadLocationException {
String annotationTypeName = isExactAnnotationType
? simpleAnnotationName
: '+' + simpleAnnotationName;
protected SymbolInformation createSymbol(Annotation node, ITypeBinding annotationType, Collection<ITypeBinding> metaAnnotations, TextDocument doc) throws BadLocationException {
String annotationTypeName = annotationType.getName();
Collection<String> metaAnnotationNames = metaAnnotations.stream()
.map(ITypeBinding::getName)
.collect(Collectors.toList());
String beanName = getBeanName(node);
String beanType = getBeanType(node);
SymbolInformation symbol = new SymbolInformation(
beanLabel("+", annotationTypeName, beanName, beanType), SymbolKind.Interface,
beanLabel("+", annotationTypeName, metaAnnotationNames, beanName, beanType), SymbolKind.Interface,
new Location(doc.getUri(), doc.toRange(node.getStartPosition(), node.getLength())));
return symbol;
}
protected boolean isExactAnnotationType(ITypeBinding actualAnnotationType) {
return actualAnnotationType.getQualifiedName().equals(annotationName);
}
protected String beanLabel(String searchPrefix, String annotationTypeName, String beanName, String beanType) {
protected String beanLabel(String searchPrefix, String annotationTypeName, Collection<String> metaAnnotationNames, String beanName, String beanType) {
StringBuilder symbolLabel = new StringBuilder();
symbolLabel.append("@");
symbolLabel.append(searchPrefix);
@@ -84,6 +71,18 @@ public class ComponentSymbolProvider implements SymbolProvider {
symbolLabel.append('\'');
symbolLabel.append(" (@");
symbolLabel.append(annotationTypeName);
if (!metaAnnotationNames.isEmpty()) {
symbolLabel.append(" <: ");
boolean first = true;
for (String ma : metaAnnotationNames) {
if (!first) {
symbolLabel.append(", ");
}
symbolLabel.append("@");
symbolLabel.append(ma);
first = false;
}
}
symbolLabel.append(") ");
symbolLabel.append(beanType);
return symbolLabel.toString();
@@ -113,9 +112,4 @@ public class ComponentSymbolProvider implements SymbolProvider {
return null;
}
@Override
public String toString() {
return "ComponentSymbolProvider("+simpleAnnotationName+")";
}
}

View File

@@ -23,6 +23,6 @@ import org.springframework.ide.vscode.commons.util.text.TextDocument;
*/
public interface SymbolProvider {
Collection<SymbolInformation> getSymbols(Annotation node, ITypeBinding typeBinding, TextDocument doc);
Collection<SymbolInformation> getSymbols(Annotation node, ITypeBinding typeBinding, Collection<ITypeBinding> metaAnnotations, TextDocument doc);
}

View File

@@ -41,7 +41,7 @@ import org.springframework.ide.vscode.commons.util.text.TextDocument;
public class RequestMappingSymbolProvider implements SymbolProvider {
@Override
public Collection<SymbolInformation> getSymbols(Annotation node, ITypeBinding annotationType, TextDocument doc) {
public Collection<SymbolInformation> getSymbols(Annotation node, ITypeBinding annotationType, Collection<ITypeBinding> metaAnnotations, TextDocument doc) {
if (node.getParent() instanceof MethodDeclaration) {
try {
Location location = new Location(doc.getUri(), doc.toRange(node.getStartPosition(), node.getLength()));

View File

@@ -48,7 +48,8 @@ import org.eclipse.lsp4j.SymbolInformation;
import org.eclipse.lsp4j.SymbolKind;
import org.eclipse.lsp4j.TextDocumentIdentifier;
import org.springframework.ide.vscode.boot.java.BootJavaLanguageServer;
import org.springframework.ide.vscode.boot.java.annotations.AnnotationHierarchyAwareFactoryManager;
import org.springframework.ide.vscode.boot.java.annotations.AnnotationHierarchies;
import org.springframework.ide.vscode.boot.java.annotations.AnnotationHierarchyAwareLookup;
import org.springframework.ide.vscode.boot.java.handlers.SymbolProvider;
import org.springframework.ide.vscode.commons.java.IClasspath;
import org.springframework.ide.vscode.commons.java.IJavaProject;
@@ -67,7 +68,7 @@ public class SpringIndexer {
private BootJavaLanguageServer server;
private JavaProjectFinder projectFinder;
private AnnotationHierarchyAwareFactoryManager<SymbolProvider> symbolProviders;
private AnnotationHierarchyAwareLookup<SymbolProvider> symbolProviders;
private List<SymbolInformation> symbols;
private ConcurrentMap<String, List<SymbolInformation>> symbolsByDoc;
@@ -98,7 +99,7 @@ public class SpringIndexer {
};
public SpringIndexer(BootJavaLanguageServer server, JavaProjectFinder projectFinder, AnnotationHierarchyAwareFactoryManager<SymbolProvider> specificProviders) {
public SpringIndexer(BootJavaLanguageServer server, JavaProjectFinder projectFinder, AnnotationHierarchyAwareLookup<SymbolProvider> specificProviders) {
this.server = server;
this.projectFinder = projectFinder;
this.symbolProviders = specificProviders;
@@ -384,10 +385,11 @@ public class SpringIndexer {
if (typeBinding != null) {
Collection<SymbolProvider> providers = symbolProviders.get(typeBinding);
Collection<ITypeBinding> metaAnnotations = AnnotationHierarchies.getMetaAnnotations(typeBinding, symbolProviders::containsKey);
if (!providers.isEmpty()) {
TextDocument doc = getTempTextDocument(docURI, docRef, content);
for (SymbolProvider provider : providers) {
Collection<SymbolInformation> sbls = provider.getSymbols(node, typeBinding, doc);
Collection<SymbolInformation> sbls = provider.getSymbols(node, typeBinding, metaAnnotations, doc);
if (sbls != null) {
sbls.forEach(symbol -> {
symbols.add(symbol);

View File

@@ -10,47 +10,37 @@
*******************************************************************************/
package org.springframework.ide.vscode.boot.java.beans.test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import java.io.File;
import java.util.Collection;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import org.eclipse.lsp4j.SymbolInformation;
import org.junit.Before;
import org.junit.Test;
import org.springframework.ide.vscode.boot.java.Annotations;
import org.springframework.ide.vscode.boot.java.annotations.AnnotationHierarchyAwareFactoryManager;
import org.springframework.ide.vscode.boot.java.annotations.AnnotationHierarchyAwareLookup;
import org.springframework.ide.vscode.boot.java.beans.BeansSymbolProvider;
import org.springframework.ide.vscode.boot.java.beans.ComponentSymbolProvider;
import org.springframework.ide.vscode.boot.java.beans.test.SpringIndexerHarness.TestSymbolInfo;
import org.springframework.ide.vscode.boot.java.handlers.SymbolProvider;
import org.springframework.ide.vscode.boot.java.utils.SpringIndexer;
import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder;
import org.springframework.ide.vscode.commons.languageserver.multiroot.WorkspaceFolder;
import org.springframework.ide.vscode.project.harness.BootLanguageServerHarness;
import org.springframework.ide.vscode.project.harness.ProjectsHarness;
import com.google.common.collect.ImmutableList;
/**
* @author Martin Lippert
*/
public class SpringIndexerBeansTest {
private AnnotationHierarchyAwareFactoryManager<SymbolProvider> symbolProviders;
private AnnotationHierarchyAwareLookup<SymbolProvider> symbolProviders;
private BootLanguageServerHarness harness;
private JavaProjectFinder projectFinder;
@Before
public void setup() throws Exception {
symbolProviders = new AnnotationHierarchyAwareFactoryManager<>();
symbolProviders = new AnnotationHierarchyAwareLookup<>();
symbolProviders.put(Annotations.BEAN, new BeansSymbolProvider());
symbolProviders.putFactory(Annotations.COMPONENT, ComponentSymbolProvider::new);
symbolProviders.put(Annotations.COMPONENT, new ComponentSymbolProvider());
harness = BootLanguageServerHarness.builder().build();
projectFinder = harness.getProjectFinder();
@@ -65,9 +55,7 @@ public class SpringIndexerBeansTest {
String uriPrefix = "file://" + directory.getAbsolutePath();
indexer.assertDocumentSymbols(uriPrefix + "/src/main/java/org/test/SimpleConfiguration.java",
symbol("@Configuration", "@+ 'simpleConfiguration' (@+Component) SimpleConfiguration"),
symbol("@Configuration", "@+ 'simpleConfiguration' (@+Configuration) SimpleConfiguration"),
symbol("@Configuration", "@+ 'simpleConfiguration' (@Configuration) SimpleConfiguration"),
symbol("@Configuration", "@+ 'simpleConfiguration' (@Configuration <: @Component) SimpleConfiguration"),
symbol("@Bean", "@+ 'simpleBean' (@Bean) BeanClass")
);
}
@@ -80,9 +68,7 @@ public class SpringIndexerBeansTest {
String uriPrefix = "file://" + directory.getAbsolutePath();
String docUri = uriPrefix + "/src/main/java/org/test/SpecialConfiguration.java";
indexer.assertDocumentSymbols(docUri,
symbol("@Configuration", "@+ 'specialConfiguration' (@+Component) SpecialConfiguration"),
symbol("@Configuration", "@+ 'specialConfiguration' (@+Configuration) SpecialConfiguration"),
symbol("@Configuration", "@+ 'specialConfiguration' (@Configuration) SpecialConfiguration"),
symbol("@Configuration", "@+ 'specialConfiguration' (@Configuration <: @Component) SpecialConfiguration"),
// @Bean("implicitNamedBean")
symbol("implicitNamedBean", "@+ 'implicitNamedBean' (@Bean) BeanClass"),
@@ -111,10 +97,7 @@ public class SpringIndexerBeansTest {
String uriPrefix = "file://" + directory.getAbsolutePath();
indexer.assertDocumentSymbols(uriPrefix + "/src/main/java/org/test/FunctionClass.java",
symbol("@Configuration", "@+ 'functionClass' (@+Component) FunctionClass"),
symbol("@Configuration", "@+ 'functionClass' (@+Configuration) FunctionClass"),
symbol("@Configuration", "@+ 'functionClass' (@Configuration) FunctionClass"),
symbol("@Configuration", "@+ 'functionClass' (@Configuration <: @Component) FunctionClass"),
symbol("@Bean", "@> 'uppercase' (@Bean) Function<String,String>")
);
}
@@ -127,7 +110,6 @@ public class SpringIndexerBeansTest {
String uriPrefix = "file://" + directory.getAbsolutePath();
indexer.assertDocumentSymbols(uriPrefix + "/src/main/java/org/test/SimpleComponent.java",
symbol("@Component", "@+ 'simpleComponent' (@+Component) SimpleComponent"),
symbol("@Component", "@+ 'simpleComponent' (@Component) SimpleComponent")
);
// List<? extends SymbolInformation> symbols = indexer.getSymbols(uriPrefix + "/src/main/java/org/test/SimpleComponent.java");
@@ -143,9 +125,7 @@ public class SpringIndexerBeansTest {
String uriPrefix = "file://" + directory.getAbsolutePath();
String docUri = uriPrefix + "/src/main/java/org/test/SimpleController.java";
indexer.assertDocumentSymbols(docUri,
symbol("@Controller", "@+ 'simpleController' (@+Component) SimpleController"),
symbol("@Controller", "@+ 'simpleController' (@+Controller) SimpleController"),
symbol("@Controller", "@+ 'simpleController' (@Controller) SimpleController")
symbol("@Controller", "@+ 'simpleController' (@Controller <: @Component) SimpleController")
);
}
@@ -157,10 +137,7 @@ public class SpringIndexerBeansTest {
String uriPrefix = "file://" + directory.getAbsolutePath();
String docUri = uriPrefix + "/src/main/java/org/test/SimpleRestController.java";
indexer.assertDocumentSymbols(docUri,
symbol("@RestController", "@+ 'simpleRestController' (@+Component) SimpleRestController"),
symbol("@RestController", "@+ 'simpleRestController' (@+Controller) SimpleRestController"),
symbol("@RestController", "@+ 'simpleRestController' (@+RestController) SimpleRestController"),
symbol("@RestController", "@+ 'simpleRestController' (@RestController) SimpleRestController")
symbol("@RestController", "@+ 'simpleRestController' (@RestController <: @Controller, @Component) SimpleRestController")
);
}

View File

@@ -25,7 +25,7 @@ import org.apache.commons.io.IOUtils;
import org.eclipse.lsp4j.Range;
import org.eclipse.lsp4j.SymbolInformation;
import org.springframework.ide.vscode.boot.java.BootJavaLanguageServer;
import org.springframework.ide.vscode.boot.java.annotations.AnnotationHierarchyAwareFactoryManager;
import org.springframework.ide.vscode.boot.java.annotations.AnnotationHierarchyAwareLookup;
import org.springframework.ide.vscode.boot.java.handlers.SymbolProvider;
import org.springframework.ide.vscode.boot.java.utils.SpringIndexer;
import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder;
@@ -106,7 +106,7 @@ public class SpringIndexerHarness {
private SpringIndexer indexer;
public SpringIndexerHarness(BootJavaLanguageServer server, JavaProjectFinder projectFinder, AnnotationHierarchyAwareFactoryManager<SymbolProvider> symbolProviders) {
public SpringIndexerHarness(BootJavaLanguageServer server, JavaProjectFinder projectFinder, AnnotationHierarchyAwareLookup<SymbolProvider> symbolProviders) {
this.indexer = new SpringIndexer(server, projectFinder, symbolProviders);
}

View File

@@ -65,11 +65,11 @@ public class SpringIndexerTest {
List<? extends SymbolInformation> allSymbols = indexer().getAllSymbols("");
assertEquals(10, allSymbols.size());
assertEquals(6, allSymbols.size());
String uriPrefix = "file://" + directory.getAbsolutePath();
assertTrue(containsSymbol(allSymbols, "@+ 'mainClass' (@SpringBootApplication) MainClass", uriPrefix + "/src/main/java/org/test/MainClass.java", 6, 0, 6, 22));
assertTrue(containsSymbol(allSymbols, "@+ 'mainClass' (@SpringBootApplication <: @SpringBootConfiguration, @Configuration, @Component) MainClass", uriPrefix + "/src/main/java/org/test/MainClass.java", 6, 0, 6, 22));
assertTrue(containsSymbol(allSymbols, "@/embedded-foo-mapping -- (no method defined)", uriPrefix + "/src/main/java/org/test/MainClass.java", 17, 1, 17, 41));
assertTrue(containsSymbol(allSymbols, "@/foo-root-mapping/embedded-foo-mapping-with-root -- (no method defined)", uriPrefix + "/src/main/java/org/test/MainClass.java", 27, 1, 27, 51));
assertTrue(containsSymbol(allSymbols, "@/mapping1 -- (no method defined)", uriPrefix + "/src/main/java/org/test/SimpleMappingClass.java", 6, 1, 6, 28));
@@ -85,12 +85,8 @@ public class SpringIndexerTest {
String uriPrefix = "file://" + directory.getAbsolutePath();
List<? extends SymbolInformation> symbols = indexer().getSymbols(uriPrefix + "/src/main/java/org/test/MainClass.java");
assertEquals(7, symbols.size());
assertTrue(containsSymbol(symbols, "@+ 'mainClass' (@SpringBootApplication) MainClass", uriPrefix + "/src/main/java/org/test/MainClass.java", 6, 0, 6, 22));
assertTrue(containsSymbol(symbols, "@+ 'mainClass' (@+SpringBootApplication) MainClass", uriPrefix + "/src/main/java/org/test/MainClass.java", 6, 0, 6, 22));
assertTrue(containsSymbol(symbols, "@+ 'mainClass' (@+SpringBootConfiguration) MainClass", uriPrefix + "/src/main/java/org/test/MainClass.java", 6, 0, 6, 22));
assertTrue(containsSymbol(symbols, "@+ 'mainClass' (@+Component) MainClass", uriPrefix + "/src/main/java/org/test/MainClass.java", 6, 0, 6, 22));
assertTrue(containsSymbol(symbols, "@+ 'mainClass' (@+Configuration) MainClass", uriPrefix + "/src/main/java/org/test/MainClass.java", 6, 0, 6, 22));
assertEquals(3, symbols.size());
assertTrue(containsSymbol(symbols, "@+ 'mainClass' (@SpringBootApplication <: @SpringBootConfiguration, @Configuration, @Component) MainClass", uriPrefix + "/src/main/java/org/test/MainClass.java", 6, 0, 6, 22));
assertTrue(containsSymbol(symbols, "@/embedded-foo-mapping -- (no method defined)", uriPrefix + "/src/main/java/org/test/MainClass.java", 17, 1, 17, 41));
assertTrue(containsSymbol(symbols, "@/foo-root-mapping/embedded-foo-mapping-with-root -- (no method defined)", uriPrefix + "/src/main/java/org/test/MainClass.java", 27, 1, 27, 51));
@@ -112,11 +108,11 @@ public class SpringIndexerTest {
List<? extends SymbolInformation> allSymbols = indexer().getAllSymbols("");
assertEquals(10, allSymbols.size());
assertEquals(6, allSymbols.size());
String uriPrefix = "file://" + directory.getAbsolutePath() + "/test-annotation-indexing";
assertTrue(containsSymbol(allSymbols, "@+ 'mainClass' (@SpringBootApplication) MainClass", uriPrefix + "/src/main/java/org/test/MainClass.java", 6, 0, 6, 22));
assertTrue(containsSymbol(allSymbols, "@+ 'mainClass' (@SpringBootApplication <: @SpringBootConfiguration, @Configuration, @Component) MainClass", uriPrefix + "/src/main/java/org/test/MainClass.java", 6, 0, 6, 22));
assertTrue(containsSymbol(allSymbols, "@/embedded-foo-mapping -- (no method defined)", uriPrefix + "/src/main/java/org/test/MainClass.java", 17, 1, 17, 41));
assertTrue(containsSymbol(allSymbols, "@/foo-root-mapping/embedded-foo-mapping-with-root -- (no method defined)", uriPrefix + "/src/main/java/org/test/MainClass.java", 27, 1, 27, 51));
assertTrue(containsSymbol(allSymbols, "@/mapping1 -- (no method defined)", uriPrefix + "/src/main/java/org/test/SimpleMappingClass.java", 6, 1, 6, 28));
@@ -145,14 +141,11 @@ public class SpringIndexerTest {
// check for updated index in all symbols
List<? extends SymbolInformation> allSymbols = indexer().getAllSymbols("");
assertEquals(10, allSymbols.size());
assertEquals(6, allSymbols.size());
String uriPrefix = "file://" + directory.getAbsolutePath();
assertTrue(containsSymbol(allSymbols, "@+ 'mainClass' (@+Component) MainClass", uriPrefix + "/src/main/java/org/test/MainClass.java", 6, 0, 6, 22));
assertTrue(containsSymbol(allSymbols, "@+ 'mainClass' (@+SpringBootApplication) MainClass", uriPrefix + "/src/main/java/org/test/MainClass.java", 6, 0, 6, 22));
assertTrue(containsSymbol(allSymbols, "@+ 'mainClass' (@SpringBootApplication) MainClass", uriPrefix + "/src/main/java/org/test/MainClass.java", 6, 0, 6, 22));
assertTrue(containsSymbol(allSymbols, "@+ 'mainClass' (@+Configuration) MainClass", uriPrefix + "/src/main/java/org/test/MainClass.java", 6, 0, 6, 22));
assertTrue(containsSymbol(allSymbols, "@+ 'mainClass' (@SpringBootApplication <: @SpringBootConfiguration, @Configuration, @Component) MainClass", uriPrefix + "/src/main/java/org/test/MainClass.java", 6, 0, 6, 22));
assertTrue(containsSymbol(allSymbols, "@/embedded-foo-mapping -- (no method defined)", uriPrefix + "/src/main/java/org/test/MainClass.java", 17, 1, 17, 41));
assertTrue(containsSymbol(allSymbols, "@/foo-root-mapping/embedded-foo-mapping-with-root -- (no method defined)", uriPrefix + "/src/main/java/org/test/MainClass.java", 27, 1, 27, 51));
assertTrue(containsSymbol(allSymbols, "@/mapping1-CHANGED -- (no method defined)", uriPrefix + "/src/main/java/org/test/SimpleMappingClass.java", 6, 1, 6, 36));
@@ -168,7 +161,7 @@ public class SpringIndexerTest {
List<? extends SymbolInformation> allSymbols = indexer().getAllSymbols("mapp");
assertEquals(7, allSymbols.size());
assertEquals(6, allSymbols.size());
String uriPrefix = "file://" + directory.getAbsolutePath();
@@ -233,7 +226,7 @@ public class SpringIndexerTest {
File directory = new File(ProjectsHarness.class.getResource("/test-projects/test-annotation-indexing-parent/test-annotation-indexing/").toURI());
List<? extends SymbolInformation> allSymbols = indexer().getAllSymbols("");
assertEquals(10, allSymbols.size());
assertEquals(6, allSymbols.size());
File pomFile = directory.toPath().resolve(MavenCore.POM_XML).toFile();
@@ -244,7 +237,7 @@ public class SpringIndexerTest {
allSymbols = indexer().getAllSymbols("");
assertFalse(indexer().isInitializing());
assertEquals(10, allSymbols.size());
assertEquals(6, allSymbols.size());
}
}