GH-1425: refactored indexer mechanics to mostly work on indexer model elements instead of concrete bean objects

This commit is contained in:
Martin Lippert
2025-01-28 15:48:57 +01:00
parent ae6806bf7e
commit b9e90da776
10 changed files with 48 additions and 47 deletions

View File

@@ -15,5 +15,8 @@ import java.util.List;
public interface SpringIndexElement {
List<SpringIndexElement> getChildren();
void addChild(SpringIndexElement child);
void removeChild(SpringIndexElement doc);
}

View File

@@ -25,6 +25,7 @@ import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
@@ -83,6 +84,7 @@ import org.springframework.ide.vscode.commons.protocol.spring.Bean;
import org.springframework.ide.vscode.commons.protocol.spring.BeansParams;
import org.springframework.ide.vscode.commons.protocol.spring.MatchingBeansParams;
import org.springframework.ide.vscode.commons.protocol.spring.SpringIndex;
import org.springframework.ide.vscode.commons.protocol.spring.SpringIndexElement;
import org.springframework.ide.vscode.commons.util.Futures;
import org.springframework.ide.vscode.commons.util.StringUtil;
import org.springframework.ide.vscode.commons.util.UriUtil;
@@ -166,7 +168,7 @@ public class SpringSymbolIndex implements InitializingBean, SpringIndex {
SymbolHandler handler = new SymbolHandler() {
@Override
public void addSymbols(IJavaProject project, String docURI, EnhancedSymbolInformation[] enhancedSymbols, Bean[] beanDefinitions,
public void addSymbols(IJavaProject project, String docURI, EnhancedSymbolInformation[] enhancedSymbols, List<SpringIndexElement> beanDefinitions,
List<Diagnostic> diagnostics) {
if (enhancedSymbols != null) {
@@ -174,7 +176,7 @@ public class SpringSymbolIndex implements InitializingBean, SpringIndex {
}
if (beanDefinitions != null) {
springIndex.updateBeans(project.getElementName(), docURI, beanDefinitions);
springIndex.updateElements(project.getElementName(), docURI, beanDefinitions.toArray(SpringIndexElement[]::new));
}
if (diagnostics != null) {
@@ -185,7 +187,7 @@ public class SpringSymbolIndex implements InitializingBean, SpringIndex {
@Override
public void addSymbols(IJavaProject project, EnhancedSymbolInformation[] enhancedSymbols,
Bean[] beanDefinitions, Map<String, List<Diagnostic>> diagnosticsPerDoc) {
Map<String, List<SpringIndexElement>> beanDefinitionsByDoc, Map<String, List<Diagnostic>> diagnosticsPerDoc) {
if (enhancedSymbols != null) {
@@ -207,21 +209,14 @@ public class SpringSymbolIndex implements InitializingBean, SpringIndex {
}
}
if (beanDefinitions != null) {
if (beanDefinitionsByDoc != null) {
// organize beans per doc URI
Map<String, List<Bean>> beansPerDoc = new HashMap<>();
for (Bean bean : beanDefinitions) {
String docURI = bean.getLocation().getUri();
beansPerDoc.computeIfAbsent(docURI, k -> new ArrayList<>()).add(bean);
}
// add beans per doc URI
for (Map.Entry<String, List<Bean>> entry : beansPerDoc.entrySet()) {
for (Entry<String, List<SpringIndexElement>> entry : beanDefinitionsByDoc.entrySet()) {
String docURI = entry.getKey();
List<Bean> beans = entry.getValue();
List<SpringIndexElement> elements = entry.getValue();
springIndex.updateBeans(project.getElementName(), docURI, (Bean[]) beans.toArray(new Bean[beans.size()]));
springIndex.updateElements(project.getElementName(), docURI, elements.toArray(SpringIndexElement[]::new));
}
}
@@ -236,7 +231,7 @@ public class SpringSymbolIndex implements InitializingBean, SpringIndex {
@Override
public void removeSymbols(IJavaProject project, String docURI) {
SpringSymbolIndex.this.removeSymbolsByDoc(project, docURI);
springIndex.removeBeans(project.getElementName(), docURI);
springIndex.removeElements(project.getElementName(), docURI);
// TODO remove diagnostics ?!? maybe, maybe not
@@ -382,11 +377,14 @@ public class SpringSymbolIndex implements InitializingBean, SpringIndex {
private CompletableFuture<Void> _initializeProject(IJavaProject project, boolean clean) {
try {
if (SpringProjectUtil.isBootProject(project) || SpringProjectUtil.isSpringProject(project)) {
if (project.getElementName() == null) {
// Projects indexed by name. No name - no index for it
log.debug("Project with NULL name is being initialized");
return CompletableFuture.completedFuture(null);
} else {
synchronized(this) { // synchronized since the `indexers` array can change via a settings change
@SuppressWarnings("unchecked")
CompletableFuture<Void>[] futures = new CompletableFuture[this.indexers.length + 1];
@@ -394,7 +392,7 @@ public class SpringSymbolIndex implements InitializingBean, SpringIndex {
// clean future
futures[0] = CompletableFuture.runAsync(() -> {
removeSymbolsByProject(project);
springIndex.removeBeans(project.getElementName());
springIndex.removeProject(project.getElementName());
}, this.updateQueue);
// index futures
@@ -923,7 +921,7 @@ public class SpringSymbolIndex implements InitializingBean, SpringIndex {
try {
for (String doc : this.docURIs) {
removeSymbolsByDoc(project, doc);
springIndex.removeBeans(project.getElementName(), doc);
springIndex.removeElements(project.getElementName(), doc);
}
for (SpringIndexer index : this.indexer) {
@@ -955,7 +953,7 @@ public class SpringSymbolIndex implements InitializingBean, SpringIndex {
for (SpringIndexer index : this.indexer) {
index.removeProject(project);
}
springIndex.removeBeans(project.getElementName());
springIndex.removeProject(project.getElementName());
server.getClient().indexUpdated();
log.debug("{} completed", this);

View File

@@ -56,23 +56,23 @@ public class SpringMetamodelIndex {
projectRootElements.put(projectName, projectRoot);
}
public void updateBeans(String projectName, String docURI, Bean[] beanDefinitions) {
public void updateElements(String projectName, String docURI, SpringIndexElement[] beanDefinitions) {
ProjectElement project = this.projectRootElements.computeIfAbsent(projectName, name -> new ProjectElement(name));
project.removeDocument(docURI);
DocumentElement document = new DocumentElement(docURI);
for (Bean bean : beanDefinitions) {
for (SpringIndexElement bean : beanDefinitions) {
document.addChild(bean);
}
project.addChild(document);
}
public void removeBeans(String projectName) {
public void removeProject(String projectName) {
projectRootElements.remove(projectName);
}
public void removeBeans(String projectName, String docURI) {
public void removeElements(String projectName, String docURI) {
ProjectElement project = projectRootElements.get(projectName);
if (project != null) {
project.removeDocument(docURI);

View File

@@ -1,5 +1,5 @@
/*******************************************************************************
* Copyright (c) 2023 VMware, Inc.
* Copyright (c) 2023, 2025 VMware, 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
@@ -11,19 +11,19 @@
package org.springframework.ide.vscode.boot.java.beans;
import org.springframework.ide.vscode.boot.index.cache.AbstractIndexCacheable;
import org.springframework.ide.vscode.commons.protocol.spring.Bean;
import org.springframework.ide.vscode.commons.protocol.spring.SpringIndexElement;
public class CachedBean extends AbstractIndexCacheable {
private final Bean bean;
private final SpringIndexElement element;
public CachedBean(String docURI, Bean bean) {
public CachedBean(String docURI, SpringIndexElement bean) {
super(docURI);
this.bean = bean;
this.element = bean;
}
public Bean getBean() {
return this.bean;
public SpringIndexElement getBean() {
return this.element;
}
}

View File

@@ -72,7 +72,7 @@ import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFin
import org.springframework.ide.vscode.commons.languageserver.reconcile.IProblemCollector;
import org.springframework.ide.vscode.commons.languageserver.reconcile.ReconcileProblem;
import org.springframework.ide.vscode.commons.protocol.java.Classpath;
import org.springframework.ide.vscode.commons.protocol.spring.Bean;
import org.springframework.ide.vscode.commons.protocol.spring.SpringIndexElement;
import org.springframework.ide.vscode.commons.util.UriUtil;
import org.springframework.ide.vscode.commons.util.text.TextDocument;
@@ -320,7 +320,7 @@ public class SpringIndexerJava implements SpringIndexer {
// dependencyTracker.dump();
EnhancedSymbolInformation[] symbols = generatedSymbols.stream().map(cachedSymbol -> cachedSymbol.getEnhancedSymbol()).toArray(EnhancedSymbolInformation[]::new);
Bean[] beans = generatedBeans.stream().filter(cachedBean -> cachedBean.getBean() != null).map(cachedBean -> cachedBean.getBean()).toArray(Bean[]::new);
List<SpringIndexElement> beans = generatedBeans.stream().filter(cachedBean -> cachedBean.getBean() != null).map(cachedBean -> cachedBean.getBean()).toList();
List<Diagnostic> diagnostics = generatedDiagnostics.stream().filter(cachedDiagnostics -> cachedDiagnostics.getDiagnostic() != null).map(cachedDiagnostic -> cachedDiagnostic.getDiagnostic()).collect(Collectors.toList());
symbolHandler.addSymbols(project, docURI, symbols, beans, diagnostics);
@@ -436,7 +436,7 @@ public class SpringIndexerJava implements SpringIndexer {
}
EnhancedSymbolInformation[] symbols = generatedSymbols.stream().map(cachedSymbol -> cachedSymbol.getEnhancedSymbol()).toArray(EnhancedSymbolInformation[]::new);
Bean[] beans = generatedBeans.stream().filter(cachedBean -> cachedBean.getBean() != null).map(cachedBean -> cachedBean.getBean()).toArray(Bean[]::new);
Map<String, List<SpringIndexElement>> beans = generatedBeans.stream().filter(cachedBean -> cachedBean.getBean() != null).collect(Collectors.groupingBy(CachedBean::getDocURI, Collectors.mapping(CachedBean::getBean, Collectors.toList())));
Map<String, List<Diagnostic>> diagnosticsByDoc = generatedDiagnostics.stream().filter(cachedDiagnostic -> cachedDiagnostic.getDiagnostic() != null).collect(Collectors.groupingBy(CachedDiagnostics::getDocURI, Collectors.mapping(CachedDiagnostics::getDiagnostic, Collectors.toList())));
addEmptyDiagnostics(diagnosticsByDoc, javaFiles);
symbolHandler.addSymbols(project, symbols, beans, diagnosticsByDoc);
@@ -548,7 +548,7 @@ public class SpringIndexerJava implements SpringIndexer {
if (symbols != null && beans != null) {
EnhancedSymbolInformation[] enhancedSymbols = Arrays.stream(symbols).map(cachedSymbol -> cachedSymbol.getEnhancedSymbol()).toArray(EnhancedSymbolInformation[]::new);
Bean[] allBeans = Arrays.stream(beans).filter(cachedBean -> cachedBean.getBean() != null).map(cachedBean -> cachedBean.getBean()).toArray(Bean[]::new);
Map<String, List<SpringIndexElement>> allBeans = Arrays.stream(beans).filter(cachedBean -> cachedBean.getBean() != null).collect(Collectors.groupingBy(CachedBean::getDocURI, Collectors.mapping(CachedBean::getBean, Collectors.toList())));
Map<String, List<Diagnostic>> diagnosticsByDoc = Arrays.stream(diagnostics).filter(cachedDiagnostic -> cachedDiagnostic.getDiagnostic() != null).collect(Collectors.groupingBy(CachedDiagnostics::getDocURI, Collectors.mapping(CachedDiagnostics::getDiagnostic, Collectors.toList())));
addEmptyDiagnostics(diagnosticsByDoc, javaFiles);
symbolHandler.addSymbols(project, enhancedSymbols, allBeans, diagnosticsByDoc);

View File

@@ -41,7 +41,7 @@ import org.springframework.ide.vscode.commons.java.IClasspath;
import org.springframework.ide.vscode.commons.java.IClasspathUtil;
import org.springframework.ide.vscode.commons.java.IJavaProject;
import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder;
import org.springframework.ide.vscode.commons.protocol.spring.Bean;
import org.springframework.ide.vscode.commons.protocol.spring.SpringIndexElement;
import org.springframework.ide.vscode.commons.util.UriUtil;
import org.springframework.ide.vscode.commons.util.text.TextDocument;
@@ -142,7 +142,7 @@ public class SpringIndexerXML implements SpringIndexer {
if (symbols != null && beans != null) {
EnhancedSymbolInformation[] enhancedSymbols = Arrays.stream(symbols).map(cachedSymbol -> cachedSymbol.getEnhancedSymbol()).toArray(EnhancedSymbolInformation[]::new);
Bean[] allBeans = Arrays.stream(beans).filter(cachedBean -> cachedBean.getBean() != null).map(cachedBean -> cachedBean.getBean()).toArray(Bean[]::new);
Map<String, List<SpringIndexElement>> allBeans = Arrays.stream(beans).filter(cachedBean -> cachedBean.getBean() != null).collect(Collectors.groupingBy(CachedBean::getDocURI, Collectors.mapping(CachedBean::getBean, Collectors.toList())));
symbolHandler.addSymbols(project, enhancedSymbols, allBeans, null);
}
@@ -180,7 +180,7 @@ public class SpringIndexerXML implements SpringIndexer {
this.cache.update(beansCacheKey, file, updatedDoc.getLastModified(), generatedBeans, null, CachedBean.class);
EnhancedSymbolInformation[] symbols = generatedSymbols.stream().map(cachedSymbol -> cachedSymbol.getEnhancedSymbol()).toArray(EnhancedSymbolInformation[]::new);
Bean[] beans = generatedBeans.stream().filter(cachedBean -> cachedBean.getBean() != null).map(cachedBean -> cachedBean.getBean()).toArray(Bean[]::new);
List<SpringIndexElement> beans = generatedBeans.stream().filter(cachedBean -> cachedBean.getBean() != null).map(cachedBean -> cachedBean.getBean()).toList();
symbolHandler.addSymbols(project, docURI, symbols, beans, null);
}
@@ -207,7 +207,7 @@ public class SpringIndexerXML implements SpringIndexer {
this.cache.update(beansCacheKey, file, updatedDoc.getLastModified(), generatedBeans, null, CachedBean.class);
EnhancedSymbolInformation[] symbols = generatedSymbols.stream().map(cachedSymbol -> cachedSymbol.getEnhancedSymbol()).toArray(EnhancedSymbolInformation[]::new);
Bean[] beans = generatedBeans.stream().filter(cachedBean -> cachedBean.getBean() != null).map(cachedBean -> cachedBean.getBean()).toArray(Bean[]::new);
List<SpringIndexElement> beans = generatedBeans.stream().filter(cachedBean -> cachedBean.getBean() != null).map(cachedBean -> cachedBean.getBean()).toList();
symbolHandler.addSymbols(project, docURI, symbols, beans, null);
}
}

View File

@@ -16,15 +16,15 @@ import java.util.Map;
import org.eclipse.lsp4j.Diagnostic;
import org.springframework.ide.vscode.boot.java.handlers.EnhancedSymbolInformation;
import org.springframework.ide.vscode.commons.java.IJavaProject;
import org.springframework.ide.vscode.commons.protocol.spring.Bean;
import org.springframework.ide.vscode.commons.protocol.spring.SpringIndexElement;
/**
* @author Martin Lippert
*/
public interface SymbolHandler {
void addSymbols(IJavaProject project, String docURI, EnhancedSymbolInformation[] enhancedSymbols, Bean[] beanDefinitions, List<Diagnostic> diagnostics);
void addSymbols(IJavaProject project, EnhancedSymbolInformation[] enhancedSymbols, Bean[] beanDefinitions, Map<String, List<Diagnostic>> diagnosticsByDoc);
void addSymbols(IJavaProject project, String docURI, EnhancedSymbolInformation[] enhancedSymbols, List<SpringIndexElement> beanDefinitions, List<Diagnostic> diagnostics);
void addSymbols(IJavaProject project, EnhancedSymbolInformation[] enhancedSymbols, Map<String, List<SpringIndexElement>> beanDefinitionsByDoc, Map<String, List<Diagnostic>> diagnosticsByDoc);
void removeSymbols(IJavaProject project, String docURI);

View File

@@ -136,13 +136,13 @@ public class SpringMetamodelIndexTest {
Bean bean2 = new Bean("beanName2", "beanType", locationForDoc1, emptyInjectionPoints, emptySupertypes, emptyAnnotations, false);
Bean bean3 = new Bean("beanName3", "beanType", locationForDoc2, emptyInjectionPoints, emptySupertypes, emptyAnnotations, false);
index.updateBeans("someProject", locationForDoc1.getUri(), new Bean[] {bean1, bean2});
index.updateBeans("someProject", locationForDoc2.getUri(), new Bean[] {bean3});
index.updateElements("someProject", locationForDoc1.getUri(), new Bean[] {bean1, bean2});
index.updateElements("someProject", locationForDoc2.getUri(), new Bean[] {bean3});
Bean updatedBean1 = new Bean("updated1", "beanType", locationForDoc1, emptyInjectionPoints, emptySupertypes, emptyAnnotations, false);
Bean updatedBean2 = new Bean("updated2", "beanType", locationForDoc1, emptyInjectionPoints, emptySupertypes, emptyAnnotations, false);
index.updateBeans("someProject", locationForDoc1.getUri(), new Bean[] {updatedBean1, updatedBean2});
index.updateElements("someProject", locationForDoc1.getUri(), new Bean[] {updatedBean1, updatedBean2});
Bean[] beans = index.getBeansOfProject("someProject");
assertNotNull(beans);
@@ -192,7 +192,7 @@ public class SpringMetamodelIndexTest {
index.updateBeans("someProject1", new Bean[] {bean1, bean2});
index.updateBeans("someProject2", new Bean[] {bean3});
index.removeBeans("someProject1");
index.removeProject("someProject1");
Bean[] beans = index.getBeansOfProject("someProject2");
assertNotNull(beans);
@@ -214,7 +214,7 @@ public class SpringMetamodelIndexTest {
Bean bean3 = new Bean("beanName3", "beanType", locationForDoc2, emptyInjectionPoints, emptySupertypes, emptyAnnotations, false);
index.updateBeans("someProject", new Bean[] {bean1, bean2, bean3});
index.removeBeans("someProject", locationForDoc1.getUri());
index.removeElements("someProject", locationForDoc1.getUri());
Bean[] beans = index.getBeansOfProject("someProject");
assertNotNull(beans);

View File

@@ -143,7 +143,7 @@ public class DependsOnDefinitionProviderTest {
List<Bean> beansOfDoc = new ArrayList<>(List.of(springIndex.getBeansOfDocument(expectedDefinitionUri)));
beansOfDoc.add(new Bean("bean1", "type", new Location(expectedDefinitionUri, new Range(new Position(20, 1), new Position(20, 10))), null, null, null, false));
springIndex.updateBeans(project.getElementName(), expectedDefinitionUri, beansOfDoc.toArray(new Bean[0]));
springIndex.updateElements(project.getElementName(), expectedDefinitionUri, beansOfDoc.toArray(new Bean[0]));
Bean[] beans = springIndex.getBeansWithName(project.getElementName(), "bean1");
assertEquals(2, beans.length);

View File

@@ -116,7 +116,7 @@ public class ResourceDefinitionProviderTest {
List<Bean> beansOfDoc = new ArrayList<>(List.of(springIndex.getBeansOfDocument(expectedDefinitionUri)));
beansOfDoc.add(new Bean("bean1", "type", new Location(expectedDefinitionUri, new Range(new Position(20, 1), new Position(20, 10))), null, null, null, false));
springIndex.updateBeans(project.getElementName(), expectedDefinitionUri, beansOfDoc.toArray(new Bean[0]));
springIndex.updateElements(project.getElementName(), expectedDefinitionUri, beansOfDoc.toArray(new Bean[0]));
Bean[] beans = springIndex.getBeansWithName(project.getElementName(), "bean1");
assertEquals(2, beans.length);