fixed an issue with the index not correctly updated when all spring index elements should be gone after an update

This commit is contained in:
Martin Lippert
2025-03-27 14:50:39 +01:00
parent ca4fc3c0f4
commit e8051b06ad
7 changed files with 83 additions and 29 deletions

View File

@@ -37,12 +37,15 @@ public class SpringMetamodelIndex {
ProjectElement project = this.projectRootElements.computeIfAbsent(projectName, name -> new ProjectElement(name));
project.removeDocument(docURI);
DocumentElement document = new DocumentElement(docURI);
for (SpringIndexElement bean : elements) {
document.addChild(bean);
}
if (elements != null && elements.length > 0) {
DocumentElement document = new DocumentElement(docURI);
for (SpringIndexElement bean : elements) {
document.addChild(bean);
}
project.addChild(document);
}
project.addChild(document);
}
public void removeElements(String projectName, String docURI) {

View File

@@ -13,7 +13,6 @@ package org.springframework.ide.vscode.boot.java.beans;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import java.util.stream.Stream;
@@ -32,13 +31,10 @@ import org.eclipse.lsp4j.jsonrpc.messages.Tuple;
import org.eclipse.lsp4j.jsonrpc.messages.Tuple.Two;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.ide.vscode.boot.index.SpringMetamodelIndex;
import org.springframework.ide.vscode.boot.java.Annotations;
import org.springframework.ide.vscode.boot.java.handlers.SymbolProvider;
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;
import org.springframework.ide.vscode.commons.protocol.spring.AnnotationAttributeValue;
import org.springframework.ide.vscode.commons.protocol.spring.AnnotationMetadata;
import org.springframework.ide.vscode.commons.protocol.spring.Bean;
import org.springframework.ide.vscode.commons.protocol.spring.InjectionPoint;
@@ -60,8 +56,6 @@ public class FeignClientSymbolProvider implements SymbolProvider {
context.getGeneratedSymbols().add(new CachedSymbol(context.getDocURI(), context.getLastModified(), symbol));
context.getBeans().add(new CachedBean(context.getDocURI(), beanDefinition));
markNewFeignConfigTypeForReconciling(beanDefinition, context);
}
}
catch (BadLocationException e) {
@@ -69,19 +63,6 @@ public class FeignClientSymbolProvider implements SymbolProvider {
}
}
private void markNewFeignConfigTypeForReconciling(Bean beanDefinition, SpringIndexerJavaContext context) {
List<String> configurationTypes = Arrays.stream(beanDefinition.getAnnotations())
.filter(annotation -> annotation.getAnnotationType().equals(Annotations.FEIGN_CLIENT))
.map(annotation -> annotation.getAttributes())
.filter(attributes -> attributes.containsKey("configuration"))
.map(attributes -> attributes.get("configuration"))
.flatMap(attributeValues -> Arrays.stream(attributeValues))
.map(attributeValue -> attributeValue.getName())
.toList();
}
private Two<WorkspaceSymbol, Bean> createSymbol(Annotation node, ITypeBinding annotationType, Collection<ITypeBinding> metaAnnotations, TextDocument doc) throws BadLocationException {
String annotationTypeName = annotationType.getName();
Collection<String> metaAnnotationNames = metaAnnotations.stream()

View File

@@ -712,8 +712,8 @@ public class SpringIndexerJava implements SpringIndexer {
IndexCacheKey diagnosticsCacheKey = getCacheKey(project, DIAGNOSTICS_KEY);
this.cache.update(diagnosticsCacheKey, javaFiles, modificationTimestamps, reconcilingResult.getGeneratedDiagnostics(), dependencyTracker.getAllDependencies(), CachedDiagnostics.class);
// publish
reconcilingResult.publishResults(symbolHandler);
// publish diagnostics
reconcilingResult.publishDiagnosticsOnly(symbolHandler);
}
private void scanAST(final SpringIndexerJavaContext context, boolean includeReconcile) {

View File

@@ -110,11 +110,30 @@ public class SpringIndexerJavaScanResult {
Map<String, List<SpringIndexElement>> allBeans = 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); // to make sure that files without diagnostics publish an empty array of diagnostics
// to make sure that files without index elements or diagnostics publish an empty array of diagnostics
addEmptyDiagnostics(diagnosticsByDoc, javaFiles);
addEmptyIndexElements(allBeans, javaFiles);
symbolHandler.addSymbols(this.project, enhancedSymbols, allBeans, diagnosticsByDoc);
}
public void publishDiagnosticsOnly(SymbolHandler symbolHandler) {
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); // to make sure that files without index elements or diagnostics publish an empty array of diagnostics
symbolHandler.addSymbols(this.project, null, null, diagnosticsByDoc);
}
private void addEmptyIndexElements(Map<String, List<SpringIndexElement>> allBeans, String[] javaFiles) {
for (int i = 0; i < javaFiles.length; i++) {
File file = new File(javaFiles[i]);
String docURI = UriUtil.toUri(file).toASCIIString();
if (!allBeans.containsKey(docURI)) {
allBeans.put(docURI, Collections.emptyList());
}
}
}
private void addEmptyDiagnostics(Map<String, List<Diagnostic>> diagnosticsByDoc, String[] javaFiles) {
for (int i = 0; i < javaFiles.length; i++) {
File file = new File(javaFiles[i]);

View File

@@ -11,7 +11,6 @@
package org.springframework.ide.vscode.boot.index.test;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNull;
import java.io.File;
import java.net.URI;
@@ -46,7 +45,7 @@ import org.springframework.test.context.junit.jupiter.SpringExtension;
@Import(SymbolProviderTestConf.class)
public class SpringMetamodelIndexingTest {
public static final int NO_OF_EXPECTED_BEANS = 28;
public static final int NO_OF_EXPECTED_BEANS = 29;
@Autowired private BootLanguageServerHarness harness;
@Autowired private JavaProjectFinder projectFinder;
@@ -142,6 +141,22 @@ public class SpringMetamodelIndexingTest {
assertEquals(2, harness.getIndexUpdatedCount()); // 1x project created, 1x document updated
}
@Test
void testUpdatedDocumentHasNoIndexElementsAnymore() throws Exception {
String changedDocURI = directory.toPath().resolve("src/main/java/org/test/SimpleComponentClass.java").toUri().toString();
Bean[] beans = springIndex.getBeansOfDocument(changedDocURI);
assertEquals(1, beans.length);
assertEquals("simpleComponentClass", beans[0].getName());
String newContent = FileUtils.readFileToString(new File(new URI(changedDocURI)), Charset.defaultCharset()).replace("@Component", "");
CompletableFuture<Void> updateFuture = indexer.updateDocument(changedDocURI, newContent, "test triggered");
updateFuture.get(5, TimeUnit.SECONDS);
Bean[] updatedBeans = springIndex.getBeansOfDocument(changedDocURI);
assertEquals(0, updatedBeans.length);
}
@Test
void testNewDocumentCreated() throws Exception {

View File

@@ -145,4 +145,32 @@ public class AddConfigurationIfBeansPresentAdvancedReconcilingTest {
assertEquals(Boot2JavaProblemType.MISSING_CONFIGURATION_ANNOTATION.getCode(), diagnostics.get(0).getCode().getLeft());
}
@Test
void testErrorAppearsWhenFeignClientAnnotationDoesAwayEntirely() throws Exception {
String feignClientDocUri = directory.toPath().resolve("src/main/java/com/example/feign/demo/FeignClientExample.java").toUri().toString();
String feignConfigRegisterd = directory.toPath().resolve("src/main/java/com/example/feign/demo/FeignConfigExample.java").toUri().toString();
// now change the config class source code and update doc
TestFileScanListener fileScanListener = new TestFileScanListener();
indexer.getJavaIndexer().setFileScanListener(fileScanListener);
String feignClientSource = FileUtils.readFileToString(UriUtil.toFile(feignClientDocUri), Charset.defaultCharset());
String updatedFeignClientSource = feignClientSource.replace("@FeignClient(name = \"stores\", configuration = FeignConfigExample.class)",
"");
CompletableFuture<Void> updateFuture = indexer.updateDocument(feignClientDocUri, updatedFeignClientSource, "test triggered");
updateFuture.get(5, TimeUnit.SECONDS);
// check if the bean registrar files have been re-scanned
fileScanListener.assertScannedUri(feignClientDocUri, 1);
fileScanListener.assertScannedUri(feignConfigRegisterd, 1);
fileScanListener.assertFileScanCount(2);
// check diagnostics result
PublishDiagnosticsParams diagnosticsResult = harness.getDiagnostics(feignConfigRegisterd);
List<Diagnostic> diagnostics = diagnosticsResult.getDiagnostics();
assertEquals(1, diagnostics.size());
assertEquals(Boot2JavaProblemType.MISSING_CONFIGURATION_ANNOTATION.getCode(), diagnostics.get(0).getCode().getLeft());
}
}

View File

@@ -0,0 +1,8 @@
package org.test;
import org.springframework.stereotype.Component;
@Component
public class SimpleComponentClass {
}