From a93a42f5ff99f6f41d729c951794a168889fd85f Mon Sep 17 00:00:00 2001 From: Martin Lippert Date: Mon, 31 Jul 2023 16:28:58 +0200 Subject: [PATCH] GH-1068: added ability to run clean index builds on project initialize + use this on config changes + publish empty diagnostics when nothing found --- .../vscode/boot/app/SpringSymbolIndex.java | 40 +++++++++++-------- .../java/utils/SpringFactoriesIndexer.java | 4 +- .../vscode/boot/java/utils/SpringIndexer.java | 2 +- .../boot/java/utils/SpringIndexerJava.java | 21 ++++++++-- .../boot/java/utils/SpringIndexerXML.java | 6 +-- ...ringValidationBeanMethodNotPublicTest.java | 15 ++++++- 6 files changed, 60 insertions(+), 28 deletions(-) diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/app/SpringSymbolIndex.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/app/SpringSymbolIndex.java index 81aa84c42..240745cc9 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/app/SpringSymbolIndex.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/app/SpringSymbolIndex.java @@ -15,6 +15,7 @@ import java.net.URI; import java.net.URISyntaxException; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; @@ -121,13 +122,13 @@ public class SpringSymbolIndex implements InitializingBean, SpringIndex { @Override public void created(IJavaProject project) { log.info("project created event: {}", project.getElementName()); - initializeProject(project); + initializeProject(project, false); } @Override public void changed(IJavaProject project) { log.info("project changed event: {}", project.getElementName()); - initializeProject(project); + initializeProject(project, false); } @Override @@ -277,14 +278,14 @@ public class SpringSymbolIndex implements InitializingBean, SpringIndex { config.addListener(evt -> { log.info("update settings of spring indexer - start"); - - server.getAsync().execute(() -> - configureIndexer(SymbolIndexConfig.builder() - .scanXml(config.isSpringXMLSupportEnabled()) - .xmlScanFolders(config.xmlBeansFoldersToScan()) - .scanTestJavaSources(config.isScanJavaTestSourcesEnabled()) - .build() - )); + + CompletableFuture.runAsync(() -> + configureIndexer(SymbolIndexConfig.builder() + .scanXml(config.isSpringXMLSupportEnabled()) + .xmlScanFolders(config.xmlBeansFoldersToScan()) + .scanTestJavaSources(config.isScanJavaTestSourcesEnabled()) + .build() + ), this.updateQueue); log.info("update settings of spring indexer - done"); }); @@ -326,6 +327,11 @@ public class SpringSymbolIndex implements InitializingBean, SpringIndex { } springIndexerJava.setScanTestJavaSources(config.isScanTestJavaSources()); } + + Collection projects = projectFinder().all(); + for (IJavaProject project : projects) { + initializeProject(project, true); + } } private void addXmlFileListeners(List globPattern) { @@ -375,8 +381,8 @@ public class SpringSymbolIndex implements InitializingBean, SpringIndex { } } - public CompletableFuture initializeProject(IJavaProject project) { - CompletableFuture cf = _initializeProject(project); + public CompletableFuture initializeProject(IJavaProject project, boolean clean) { + CompletableFuture cf = _initializeProject(project, clean); cf.thenAccept( f -> { projectInitializedFuture(project).complete(null); }); @@ -384,7 +390,7 @@ public class SpringSymbolIndex implements InitializingBean, SpringIndex { return cf; } - private CompletableFuture _initializeProject(IJavaProject project) { + private CompletableFuture _initializeProject(IJavaProject project, boolean clean) { try { if (SpringProjectUtil.isBootProject(project) || SpringProjectUtil.isSpringProject(project)) { if (project.getElementName() == null) { @@ -399,7 +405,7 @@ public class SpringSymbolIndex implements InitializingBean, SpringIndex { @SuppressWarnings("unchecked") CompletableFuture[] futures = new CompletableFuture[this.indexers.length]; for (int i = 0; i < this.indexers.length; i++) { - InitializeProject initializeItem = new InitializeProject(project, this.indexers[i]); + InitializeProject initializeItem = new InitializeProject(project, this.indexers[i], clean); futures[i] = CompletableFuture.runAsync(initializeItem, this.updateQueue); } @@ -843,10 +849,12 @@ public class SpringSymbolIndex implements InitializingBean, SpringIndex { private final IJavaProject project; private final SpringIndexer indexer; + private final boolean clean; - public InitializeProject(IJavaProject project, SpringIndexer indexer) { + public InitializeProject(IJavaProject project, SpringIndexer indexer, boolean clean) { this.project = project; this.indexer = indexer; + this.clean = clean; log.debug("{} created ", this); } @@ -854,7 +862,7 @@ public class SpringSymbolIndex implements InitializingBean, SpringIndex { public void run() { log.debug("{} starting...", this); try { - indexer.initializeProject(project); + indexer.initializeProject(project, this.clean); log.debug("{} completed", this); } catch (Throwable e) { diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/SpringFactoriesIndexer.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/SpringFactoriesIndexer.java index 3e8feabd1..49dd53ec7 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/SpringFactoriesIndexer.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/SpringFactoriesIndexer.java @@ -160,7 +160,7 @@ public class SpringFactoriesIndexer implements SpringIndexer { @Override - public void initializeProject(IJavaProject project) throws Exception { + public void initializeProject(IJavaProject project, boolean clean) throws Exception { long startTime = System.currentTimeMillis(); List files = getFiles(project); String[] filesStr = files.stream().map(f -> f.toAbsolutePath().toString()).toArray(String[]::new); @@ -170,7 +170,7 @@ public class SpringFactoriesIndexer implements SpringIndexer { IndexCacheKey cacheKey = getCacheKey(project); CachedSymbol[] symbols = this.cache.retrieveSymbols(cacheKey, filesStr, CachedSymbol.class); - if (symbols == null) { + if (symbols == null || clean) { List generatedSymbols = new ArrayList(); for (Path file : files) { diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/SpringIndexer.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/SpringIndexer.java index 86756408a..38b09b927 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/SpringIndexer.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/SpringIndexer.java @@ -25,7 +25,7 @@ public interface SpringIndexer { List computeSymbols(IJavaProject project, String docURI, String content) throws Exception; - void initializeProject(IJavaProject project) throws Exception; + void initializeProject(IJavaProject project, boolean clean) throws Exception; void removeProject(IJavaProject project) throws Exception; void updateFile(IJavaProject project, DocumentDescriptor updatedDoc, String content) throws Exception; diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/SpringIndexerJava.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/SpringIndexerJava.java index 18e068782..9ca61ca18 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/SpringIndexerJava.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/SpringIndexerJava.java @@ -137,13 +137,13 @@ public class SpringIndexerJava implements SpringIndexer { } @Override - public void initializeProject(IJavaProject project) throws Exception { + public void initializeProject(IJavaProject project, boolean clean) throws Exception { String[] files = this.getFiles(project); log.info("scan java files for symbols for project: {} - no. of files: {}", project.getElementName(), files.length); long startTime = System.currentTimeMillis(); - scanFiles(project, files); + scanFiles(project, files, clean); long endTime = System.currentTimeMillis(); log.info("scan java files for symbols for project: {} took ms: {}", project.getElementName(), endTime - startTime); @@ -413,6 +413,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> 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); IndexCacheKey symbolsCacheKey = getCacheKey(project, SYMBOL_KEY); @@ -457,7 +458,7 @@ public class SpringIndexerJava implements SpringIndexer { log.info("Finished scanning affected files {}", alreadyScannedFiles); } - private void scanFiles(IJavaProject project, String[] javaFiles) throws Exception { + private void scanFiles(IJavaProject project, String[] javaFiles, boolean clean) throws Exception { IndexCacheKey symbolsCacheKey = getCacheKey(project, SYMBOL_KEY); IndexCacheKey beansCacheKey = getCacheKey(project, BEANS_KEY); IndexCacheKey diagnosticsCacheKey = getCacheKey(project, DIAGNOSTICS_KEY); @@ -470,7 +471,7 @@ public class SpringIndexerJava implements SpringIndexer { CachedBean[] beans; CachedDiagnostics[] diagnostics; - if (cachedSymbols == null || cachedBeans == null || cachedDiagnostics == null ) { + if (clean || cachedSymbols == null || cachedBeans == null || cachedDiagnostics == null) { List generatedSymbols = new ArrayList(); List generatedBeans = new ArrayList(); List generatedDiagnostics = new ArrayList(); @@ -517,6 +518,7 @@ public class SpringIndexerJava implements SpringIndexer { 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> 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); } } @@ -559,6 +561,17 @@ public class SpringIndexerJava implements SpringIndexer { } } + private void addEmptyDiagnostics(Map> diagnosticsByDoc, String[] javaFiles) { + for (int i = 0; i < javaFiles.length; i++) { + File file = new File(javaFiles[i]); + String docURI = UriUtil.toUri(file).toASCIIString(); + + if (!diagnosticsByDoc.containsKey(docURI)) { + diagnosticsByDoc.put(docURI, Collections.emptyList()); + } + } + } + private void scanAST(final SpringIndexerJavaContext context) { context.getCu().accept(new ASTVisitor() { diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/SpringIndexerXML.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/SpringIndexerXML.java index e4e9bbcd6..20290f2ac 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/SpringIndexerXML.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/SpringIndexerXML.java @@ -104,7 +104,7 @@ public class SpringIndexerXML implements SpringIndexer { } @Override - public void initializeProject(IJavaProject project) throws Exception { + public void initializeProject(IJavaProject project, boolean clean) throws Exception { long startTime = System.currentTimeMillis(); String[] files = this.getFiles(project); @@ -116,7 +116,7 @@ public class SpringIndexerXML implements SpringIndexer { CachedSymbol[] symbols = this.cache.retrieveSymbols(symbolsCacheKey, files, CachedSymbol.class); CachedBean[] beans = this.cache.retrieveSymbols(beansCacheKey, files, CachedBean.class); - if (symbols == null || beans == null) { + if (symbols == null || beans == null || clean) { List generatedSymbols = new ArrayList(); List generatedBeans = new ArrayList(); @@ -334,7 +334,7 @@ public class SpringIndexerXML implements SpringIndexer { private void populateIndex() { for (IJavaProject project : projectFinder.all()) { try { - initializeProject(project); + initializeProject(project, true); } catch (Exception e) { log.error("{}", e); } diff --git a/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/reconcilers/test/SpringValidationBeanMethodNotPublicTest.java b/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/reconcilers/test/SpringValidationBeanMethodNotPublicTest.java index ed537181a..32e5f2d98 100644 --- a/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/reconcilers/test/SpringValidationBeanMethodNotPublicTest.java +++ b/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/java/reconcilers/test/SpringValidationBeanMethodNotPublicTest.java @@ -11,6 +11,7 @@ package org.springframework.ide.vscode.boot.java.reconcilers.test; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; import static org.junit.jupiter.api.Assertions.assertTrue; import java.io.File; @@ -67,9 +68,8 @@ public class SpringValidationBeanMethodNotPublicTest { } @Test - void testScanSimpleConfigurationClass() throws Exception { + void testFindPublicBeanMethodInConfigClass() throws Exception { String docUri = directory.toPath().resolve("src/main/java/org/test/BeanMethodNotPublic.java").toUri().toString(); - assertTrue(true); PublishDiagnosticsParams diagnosticsMessage = harness.getDiagnostics(docUri); List diagnostics = diagnosticsMessage.getDiagnostics(); @@ -86,4 +86,15 @@ public class SpringValidationBeanMethodNotPublicTest { assertEquals(1, diagnostics.size()); } + + @Test + void testPublishEmptyDiagnosticsWhenNoProblemsAreFound() throws Exception { + String docUri = directory.toPath().resolve("src/main/java/org/test/BeanClass1.java").toUri().toString(); + + PublishDiagnosticsParams diagnosticsMessage = harness.getDiagnostics(docUri); + assertNotNull(diagnosticsMessage); + + List diagnostics = diagnosticsMessage.getDiagnostics(); + assertEquals(0, diagnostics.size()); + } }