PT #165080768, #165662425: Selective Java, XML symbol scanning
This commit is contained in:
@@ -10,8 +10,13 @@
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.boot.app;
|
||||
|
||||
import java.nio.file.FileSystems;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.ListenerList;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.Settings;
|
||||
@@ -26,6 +31,8 @@ import org.springframework.stereotype.Component;
|
||||
*/
|
||||
@Component
|
||||
public class BootJavaConfig implements InitializingBean {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(BootJavaConfig.class);
|
||||
|
||||
//TODO: Consider changing this to something that raises Spring application events.
|
||||
// I.e. like described in here: https://www.baeldung.com/spring-events
|
||||
@@ -48,6 +55,27 @@ public class BootJavaConfig implements InitializingBean {
|
||||
Boolean enabled = settings.getBoolean("boot-java", "support-spring-xml-config", "on");
|
||||
return enabled != null && enabled.booleanValue();
|
||||
}
|
||||
|
||||
public boolean isScanJavaTestSourcesEnabled() {
|
||||
Boolean enabled = settings.getBoolean("boot-java", "scan-java-test-sources", "on");
|
||||
return enabled != null && enabled.booleanValue();
|
||||
}
|
||||
|
||||
public String[] xmlBeansFoldersToScan() {
|
||||
String folders = settings.getString("boot-java", "support-spring-xml-config", "scan-folders-globs");
|
||||
String[] patterns = folders == null ? new String[0] : folders.split("\\s*,\\s*");
|
||||
// Validate patterns
|
||||
List<String> validatedPatterns = new ArrayList<>(patterns.length);
|
||||
for (String pattern : patterns) {
|
||||
try {
|
||||
FileSystems.getDefault().getPathMatcher("glob:" + pattern);
|
||||
validatedPatterns.add(pattern);
|
||||
} catch (Throwable t) {
|
||||
log.error("Failed to parse glob pattern: '{}'", pattern);
|
||||
}
|
||||
}
|
||||
return validatedPatterns.toArray(new String[validatedPatterns.size()]);
|
||||
}
|
||||
|
||||
public boolean isChangeDetectionEnabled() {
|
||||
Boolean enabled = settings.getBoolean("boot-java", "change-detection", "on");
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
package org.springframework.ide.vscode.boot.app;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
@@ -48,6 +49,7 @@ import org.springframework.ide.vscode.boot.java.utils.SpringIndexerXMLNamespaceH
|
||||
import org.springframework.ide.vscode.boot.java.utils.SpringIndexerXMLNamespaceHandlerBeans;
|
||||
import org.springframework.ide.vscode.boot.java.utils.SymbolCache;
|
||||
import org.springframework.ide.vscode.boot.java.utils.SymbolHandler;
|
||||
import org.springframework.ide.vscode.boot.java.utils.SymbolIndexConfig;
|
||||
import org.springframework.ide.vscode.commons.java.IJavaProject;
|
||||
import org.springframework.ide.vscode.commons.java.SpringProjectUtil;
|
||||
import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder;
|
||||
@@ -61,6 +63,8 @@ import org.springframework.ide.vscode.commons.util.StringUtil;
|
||||
import org.springframework.ide.vscode.commons.util.text.TextDocument;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import com.google.common.base.Supplier;
|
||||
|
||||
/**
|
||||
* @author Martin Lippert
|
||||
*/
|
||||
@@ -136,12 +140,18 @@ public class SpringSymbolIndex implements InitializingBean {
|
||||
public void addSymbol(IJavaProject project, String docURI, EnhancedSymbolInformation enhancedSymbol) {
|
||||
SpringSymbolIndex.this.addSymbol(project, docURI, enhancedSymbol);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeSymbols(IJavaProject project, String docURI) {
|
||||
SpringSymbolIndex.this.removeSymbolsByDoc(project, docURI);
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
Map<String, SpringIndexerXMLNamespaceHandler> namespaceHandler = new HashMap<>();
|
||||
namespaceHandler.put("http://www.springframework.org/schema/beans", new SpringIndexerXMLNamespaceHandlerBeans());
|
||||
springIndexerXML = new SpringIndexerXML(handler, namespaceHandler, this.cache);
|
||||
springIndexerJava = new SpringIndexerJava(handler, specificProviders, this.cache);
|
||||
springIndexerXML = new SpringIndexerXML(handler, namespaceHandler, this.cache, projectFinder());
|
||||
springIndexerJava = new SpringIndexerJava(handler, specificProviders, this.cache, projectFinder());
|
||||
|
||||
this.indexer = new SpringIndexer[] {springIndexerJava};
|
||||
|
||||
@@ -166,7 +176,11 @@ public class SpringSymbolIndex implements InitializingBean {
|
||||
}
|
||||
});
|
||||
config.addListener(evt -> {
|
||||
this.configureIndexer(config.isSpringXMLSupportEnabled());
|
||||
this.configureIndexer(SymbolIndexConfig.builder()
|
||||
.scanXml(config.isSpringXMLSupportEnabled())
|
||||
.xmlScanFoldersGlobs(config.xmlBeansFoldersToScan())
|
||||
.scanTestJavaSources(config.isScanJavaTestSourcesEnabled())
|
||||
.build());
|
||||
});
|
||||
server.doOnInitialized(this::serverInitialized);
|
||||
server.onShutdown(this::shutdown);
|
||||
@@ -186,11 +200,13 @@ public class SpringSymbolIndex implements InitializingBean {
|
||||
});
|
||||
}
|
||||
|
||||
public void configureIndexer(boolean springXMLSupportEnabled) {
|
||||
public CompletableFuture<Void> configureIndexer(SymbolIndexConfig config) {
|
||||
List<CompletableFuture<?>> futuresList = new ArrayList<>();
|
||||
synchronized (this) {
|
||||
if (springXMLSupportEnabled && !(Arrays.asList(this.indexer).contains(springIndexerXML))) {
|
||||
if (config.isScanXml() && !(Arrays.asList(this.indexer).contains(springIndexerXML))) {
|
||||
this.indexer = new SpringIndexer[] {springIndexerJava, springIndexerXML};
|
||||
|
||||
futuresList.add(CompletableFuture.runAsync(() -> springIndexerXML.setScanFolderGlobs(config.getXmlScanFoldersGlobs())));
|
||||
|
||||
List<String> globPattern = Arrays.asList(springIndexerXML.getFileWatchPatterns());
|
||||
|
||||
watchXMLDeleteRegistration = getWorkspaceService().getFileObserver().onFileDeleted(globPattern, (file) -> {
|
||||
@@ -202,10 +218,11 @@ public class SpringSymbolIndex implements InitializingBean {
|
||||
watchXMLChangedRegistration = getWorkspaceService().getFileObserver().onFileChanged(globPattern, (file) -> {
|
||||
updateDocument(new TextDocumentIdentifier(file).getUri(), null);
|
||||
});
|
||||
|
||||
|
||||
}
|
||||
else if (!springXMLSupportEnabled && Arrays.asList(this.indexer).contains(springIndexerXML)) {
|
||||
else if (!config.isScanXml() && Arrays.asList(this.indexer).contains(springIndexerXML)) {
|
||||
this.indexer = new SpringIndexer[] {springIndexerJava};
|
||||
futuresList.add(CompletableFuture.runAsync(() -> springIndexerXML.setScanFolderGlobs(new String[0])));
|
||||
|
||||
getWorkspaceService().getFileObserver().unsubscribe(watchXMLChangedRegistration);
|
||||
getWorkspaceService().getFileObserver().unsubscribe(watchXMLCreatedRegistration);
|
||||
@@ -214,8 +231,12 @@ public class SpringSymbolIndex implements InitializingBean {
|
||||
watchXMLChangedRegistration = null;
|
||||
watchXMLCreatedRegistration = null;
|
||||
watchXMLDeleteRegistration = null;
|
||||
} else if (config.isScanXml()) {
|
||||
futuresList.add(CompletableFuture.runAsync(() -> springIndexerXML.setScanFolderGlobs(config.getXmlScanFoldersGlobs())));
|
||||
}
|
||||
futuresList.add(CompletableFuture.runAsync(() -> springIndexerJava.setScanTestJavaSources(config.isScanTestJavaSources())));
|
||||
}
|
||||
return CompletableFuture.allOf(futuresList.toArray(new CompletableFuture<?>[futuresList.size()]));
|
||||
}
|
||||
|
||||
public void shutdown() {
|
||||
@@ -291,7 +312,14 @@ public class SpringSymbolIndex implements InitializingBean {
|
||||
try {
|
||||
File file = new File(new URI(docURI));
|
||||
long lastModified = file.lastModified();
|
||||
String content = FileUtils.readFileToString(file);
|
||||
Supplier<String> content = () -> {
|
||||
try {
|
||||
return FileUtils.readFileToString(file);
|
||||
} catch (IOException e) {
|
||||
log.error("{}", e);
|
||||
return "";
|
||||
}
|
||||
};
|
||||
|
||||
UpdateItem updateItem = new UpdateItem(maybeProject.get(), docURI, lastModified, content, indexer);
|
||||
futures.add(CompletableFuture.runAsync(updateItem, this.updateQueue));
|
||||
@@ -323,12 +351,21 @@ public class SpringSymbolIndex implements InitializingBean {
|
||||
try {
|
||||
File file = new File(new URI(docURI));
|
||||
long lastModified = file.lastModified();
|
||||
|
||||
Supplier<String> contentSupplier = () -> {
|
||||
if (content == null) {
|
||||
try {
|
||||
return FileUtils.readFileToString(file);
|
||||
} catch (IOException e) {
|
||||
log.error("{}", e);
|
||||
return "";
|
||||
}
|
||||
} else {
|
||||
return content;
|
||||
}
|
||||
};
|
||||
|
||||
if (content == null) {
|
||||
content = FileUtils.readFileToString(file);
|
||||
}
|
||||
|
||||
UpdateItem updateItem = new UpdateItem(maybeProject.get(), docURI, lastModified, content, indexer);
|
||||
UpdateItem updateItem = new UpdateItem(maybeProject.get(), docURI, lastModified, contentSupplier, indexer);
|
||||
futures.add(CompletableFuture.runAsync(updateItem, this.updateQueue));
|
||||
}
|
||||
catch (Exception e) {
|
||||
@@ -488,12 +525,12 @@ public class SpringSymbolIndex implements InitializingBean {
|
||||
private class UpdateItem implements Runnable {
|
||||
|
||||
private final String docURI;
|
||||
private final String content;
|
||||
private final Supplier<String> content;
|
||||
private final IJavaProject project;
|
||||
private final SpringIndexer indexer;
|
||||
private final long lastModified;
|
||||
|
||||
public UpdateItem(IJavaProject project, String docURI, long lastModified, String content, SpringIndexer indexer) {
|
||||
public UpdateItem(IJavaProject project, String docURI, long lastModified, Supplier<String> content, SpringIndexer indexer) {
|
||||
this.project = project;
|
||||
this.docURI = docURI;
|
||||
this.lastModified = lastModified;
|
||||
|
||||
@@ -12,6 +12,8 @@ package org.springframework.ide.vscode.boot.java.utils;
|
||||
|
||||
import org.springframework.ide.vscode.commons.java.IJavaProject;
|
||||
|
||||
import com.google.common.base.Supplier;
|
||||
|
||||
/**
|
||||
* @author Martin Lippert
|
||||
*/
|
||||
@@ -23,7 +25,7 @@ public interface SpringIndexer {
|
||||
void initializeProject(IJavaProject project) throws Exception;
|
||||
void removeProject(IJavaProject project) throws Exception;
|
||||
|
||||
void updateFile(IJavaProject project, String docURI, long lastModified, String content) throws Exception;
|
||||
void updateFile(IJavaProject project, String docURI, long lastModified, Supplier<String> content) throws Exception;
|
||||
void removeFile(IJavaProject project, String docURI) throws Exception;
|
||||
|
||||
|
||||
|
||||
@@ -11,8 +11,10 @@
|
||||
package org.springframework.ide.vscode.boot.java.utils;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
@@ -23,6 +25,7 @@ import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import org.apache.commons.codec.digest.DigestUtils;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.eclipse.jdt.core.JavaCore;
|
||||
import org.eclipse.jdt.core.dom.AST;
|
||||
import org.eclipse.jdt.core.dom.ASTParser;
|
||||
@@ -46,9 +49,12 @@ import org.springframework.ide.vscode.boot.java.handlers.SymbolProvider;
|
||||
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.util.UriUtil;
|
||||
import org.springframework.ide.vscode.commons.util.text.TextDocument;
|
||||
|
||||
import com.google.common.base.Supplier;
|
||||
|
||||
/**
|
||||
* @author Martin Lippert
|
||||
*/
|
||||
@@ -63,11 +69,15 @@ public class SpringIndexerJava implements SpringIndexer {
|
||||
private final SymbolHandler symbolHandler;
|
||||
private final AnnotationHierarchyAwareLookup<SymbolProvider> symbolProviders;
|
||||
private final SymbolCache cache;
|
||||
private final JavaProjectFinder projectFinder;
|
||||
private boolean scanTestJavaSources = false;
|
||||
|
||||
public SpringIndexerJava(SymbolHandler symbolHandler, AnnotationHierarchyAwareLookup<SymbolProvider> symbolProviders, SymbolCache cache) {
|
||||
public SpringIndexerJava(SymbolHandler symbolHandler, AnnotationHierarchyAwareLookup<SymbolProvider> symbolProviders, SymbolCache cache,
|
||||
JavaProjectFinder projectFimder) {
|
||||
this.symbolHandler = symbolHandler;
|
||||
this.symbolProviders = symbolProviders;
|
||||
this.cache = cache;
|
||||
this.projectFinder = projectFimder;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -100,8 +110,10 @@ public class SpringIndexerJava implements SpringIndexer {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateFile(IJavaProject project, String docURI, long lastModified, String content) throws Exception {
|
||||
scanFile(project, docURI, lastModified, content);
|
||||
public void updateFile(IJavaProject project, String docURI, long lastModified, Supplier<String> content) throws Exception {
|
||||
if (shouldProcessDocument(project, docURI)) {
|
||||
scanFile(project, docURI, lastModified, content.get());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -110,6 +122,14 @@ public class SpringIndexerJava implements SpringIndexer {
|
||||
String file = new File(new URI(docURI)).getAbsolutePath();
|
||||
this.cache.removeFile(cacheKey, file);
|
||||
}
|
||||
|
||||
private boolean shouldProcessDocument(IJavaProject project, String docURI) {
|
||||
Path path = Paths.get(URI.create(docURI));
|
||||
return foldersToScan(project)
|
||||
.filter(sourceFolder -> path.startsWith(sourceFolder.toPath()))
|
||||
.findFirst()
|
||||
.isPresent();
|
||||
}
|
||||
|
||||
private void scanFile(IJavaProject project, String docURI, long lastModified, String content) throws Exception {
|
||||
ASTParser parser = createParser(project, false);
|
||||
@@ -355,13 +375,27 @@ public class SpringIndexerJava implements SpringIndexer {
|
||||
.map(file -> file.getAbsolutePath())
|
||||
.toArray(String[]::new);
|
||||
}
|
||||
|
||||
private Stream<File> foldersToScan(IJavaProject project) {
|
||||
IClasspath classpath = project.getClasspath();
|
||||
return scanTestJavaSources ? IClasspathUtil.getProjectJavaSourceFolders(classpath)
|
||||
: IClasspathUtil.getProjectJavaSourceFoldersWithoutTests(classpath);
|
||||
}
|
||||
|
||||
private String[] getFiles(IJavaProject project) throws Exception {
|
||||
return Files.walk(Paths.get(project.getLocationUri()))
|
||||
.filter(path -> path.getFileName().toString().endsWith(".java"))
|
||||
.filter(Files::isRegularFile)
|
||||
.map(path -> path.toAbsolutePath().toString())
|
||||
.toArray(String[]::new);
|
||||
return foldersToScan(project)
|
||||
.flatMap(folder -> {
|
||||
try {
|
||||
return Files.walk(folder.toPath());
|
||||
} catch (IOException e) {
|
||||
log.error("{}", e);
|
||||
return Stream.empty();
|
||||
}
|
||||
})
|
||||
.filter(path -> path.getFileName().toString().endsWith(".java"))
|
||||
.filter(Files::isRegularFile)
|
||||
.map(path -> path.toAbsolutePath().toString())
|
||||
.toArray(String[]::new);
|
||||
}
|
||||
|
||||
private SymbolCacheKey getCacheKey(IJavaProject project) {
|
||||
@@ -376,4 +410,65 @@ public class SpringIndexerJava implements SpringIndexer {
|
||||
return new SymbolCacheKey(project.getElementName() + "-java-", DigestUtils.md5Hex(classpathIdentifier).toUpperCase());
|
||||
}
|
||||
|
||||
public void setScanTestJavaSources(boolean scanTestJavaSources) {
|
||||
if (this.scanTestJavaSources != scanTestJavaSources) {
|
||||
this.scanTestJavaSources = scanTestJavaSources;
|
||||
if (scanTestJavaSources) {
|
||||
addTestsJavaSourcesToIndex();
|
||||
} else {
|
||||
removeTestJavaSourcesFromIndex();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void removeTestJavaSourcesFromIndex() {
|
||||
for (IJavaProject project : projectFinder.all()) {
|
||||
Path[] testJavaFiles = IClasspathUtil.getProjectTestJavaSources(project.getClasspath()).flatMap(folder -> {
|
||||
try {
|
||||
return Files.walk(folder.toPath());
|
||||
} catch (IOException e) {
|
||||
log.error("{}", e);
|
||||
return Stream.empty();
|
||||
}
|
||||
})
|
||||
.filter(path -> path.getFileName().toString().endsWith(".java"))
|
||||
.filter(Files::isRegularFile).toArray(Path[]::new);
|
||||
|
||||
try {
|
||||
for (Path path : testJavaFiles) {
|
||||
URI docUri = UriUtil.toUri(path.toFile());
|
||||
symbolHandler.removeSymbols(project, docUri.toString());
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("{}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void addTestsJavaSourcesToIndex() {
|
||||
for (IJavaProject project : projectFinder.all()) {
|
||||
Path[] testJavaFiles = IClasspathUtil.getProjectTestJavaSources(project.getClasspath()).flatMap(folder -> {
|
||||
try {
|
||||
return Files.walk(folder.toPath());
|
||||
} catch (IOException e) {
|
||||
log.error("{}", e);
|
||||
return Stream.empty();
|
||||
}
|
||||
})
|
||||
.filter(path -> path.getFileName().toString().endsWith(".java"))
|
||||
.filter(Files::isRegularFile).toArray(Path[]::new);
|
||||
|
||||
try {
|
||||
for (Path path : testJavaFiles) {
|
||||
File file = path.toFile();
|
||||
URI docUri = UriUtil.toUri(file);
|
||||
String content = FileUtils.readFileToString(file);
|
||||
scanFile(project, docUri.toString(), file.lastModified(), content);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("{}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -13,13 +13,16 @@ package org.springframework.ide.vscode.boot.java.utils;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.net.URI;
|
||||
import java.nio.file.FileSystems;
|
||||
import java.nio.file.FileVisitResult;
|
||||
import java.nio.file.FileVisitor;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.PathMatcher;
|
||||
import java.nio.file.Paths;
|
||||
import java.nio.file.attribute.BasicFileAttributes;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.atomic.AtomicReference;
|
||||
@@ -36,9 +39,11 @@ import org.slf4j.LoggerFactory;
|
||||
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.util.UriUtil;
|
||||
import org.springframework.ide.vscode.commons.util.text.TextDocument;
|
||||
|
||||
import com.google.common.base.Supplier;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
|
||||
/**
|
||||
@@ -51,16 +56,39 @@ public class SpringIndexerXML implements SpringIndexer {
|
||||
private final SymbolHandler symbolHandler;
|
||||
private final Map<String, SpringIndexerXMLNamespaceHandler> namespaceHandler;
|
||||
private final SymbolCache cache;
|
||||
private final JavaProjectFinder projectFinder;
|
||||
|
||||
private String[] scanFolderGlobs = new String[0];
|
||||
|
||||
public SpringIndexerXML(SymbolHandler handler, Map<String, SpringIndexerXMLNamespaceHandler> namespaceHandler, SymbolCache cache) {
|
||||
public SpringIndexerXML(SymbolHandler handler, Map<String, SpringIndexerXMLNamespaceHandler> namespaceHandler,
|
||||
SymbolCache cache, JavaProjectFinder projectFinder) {
|
||||
this.symbolHandler = handler;
|
||||
this.namespaceHandler = namespaceHandler;
|
||||
this.cache = cache;
|
||||
this.projectFinder = projectFinder;
|
||||
}
|
||||
|
||||
public void setScanFolderGlobs(String[] scanFolderGlobs) {
|
||||
if (!Arrays.equals(this.scanFolderGlobs, scanFolderGlobs)) {
|
||||
clearIndex();
|
||||
this.scanFolderGlobs = scanFolderGlobs;
|
||||
populateIndex();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getFileWatchPatterns() {
|
||||
return new String[] {"**/*.xml"};
|
||||
String[] patterns = new String[scanFolderGlobs.length];
|
||||
for (int i = 0; i < scanFolderGlobs.length; i++) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
sb.append(scanFolderGlobs[i]);
|
||||
if (scanFolderGlobs[i].charAt(scanFolderGlobs[i].length() - 1) != '/') {
|
||||
sb.append('/');
|
||||
}
|
||||
sb.append("*.xml");
|
||||
patterns[i] = sb.toString();
|
||||
}
|
||||
return patterns;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -112,11 +140,11 @@ public class SpringIndexerXML implements SpringIndexer {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateFile(IJavaProject project, String docURI, long lastModified, String content) throws Exception {
|
||||
public void updateFile(IJavaProject project, String docURI, long lastModified, Supplier<String> content) throws Exception {
|
||||
|
||||
List<CachedSymbol> generatedSymbols = new ArrayList<CachedSymbol>();
|
||||
|
||||
scanFile(project, content, docURI, lastModified, generatedSymbols);
|
||||
scanFile(project, content.get(), docURI, lastModified, generatedSymbols);
|
||||
|
||||
SymbolCacheKey cacheKey = getCacheKey(project);
|
||||
String file = new File(new URI(docURI)).getAbsolutePath();
|
||||
@@ -188,20 +216,35 @@ public class SpringIndexerXML implements SpringIndexer {
|
||||
}
|
||||
|
||||
private String[] getFiles(IJavaProject project) throws Exception {
|
||||
List<Path> outputFolders = IClasspathUtil.getOutputFolders(project.getClasspath()).map(f -> f.toPath()).collect(Collectors.toList());
|
||||
String[] globs = scanFolderGlobs;
|
||||
if (globs.length == 0) {
|
||||
return new String[0];
|
||||
}
|
||||
List<PathMatcher> matchers = new ArrayList<>(globs.length);
|
||||
for (String glob : globs) {
|
||||
matchers.add(FileSystems.getDefault().getPathMatcher("glob:" + glob));
|
||||
}
|
||||
|
||||
ImmutableList.Builder<String> builder = ImmutableList.builder();
|
||||
Files.walkFileTree(Paths.get(project.getLocationUri()), new FileVisitor<Path>() {
|
||||
|
||||
@Override
|
||||
public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) throws IOException {
|
||||
return outputFolders.contains(dir) ? FileVisitResult.SKIP_SUBTREE : FileVisitResult.CONTINUE;
|
||||
return FileVisitResult.CONTINUE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IOException {
|
||||
String fileName = file.getFileName().toString();
|
||||
if (fileName.endsWith(".xml") && !"pom.xml".equals(fileName)) {
|
||||
builder.add(file.toAbsolutePath().toString());
|
||||
if (fileName.endsWith(".xml")) {
|
||||
Path parent = file.getParent();
|
||||
if (parent != null) {
|
||||
for (PathMatcher matcher : matchers) {
|
||||
if (matcher.matches(parent)) {
|
||||
builder.add(file.toAbsolutePath().toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return FileVisitResult.CONTINUE;
|
||||
}
|
||||
@@ -232,5 +275,29 @@ public class SpringIndexerXML implements SpringIndexer {
|
||||
|
||||
return new SymbolCacheKey(project.getElementName() + "-xml-", DigestUtils.md5Hex(classpathIdentifier).toUpperCase());
|
||||
}
|
||||
|
||||
|
||||
private void clearIndex() {
|
||||
for (IJavaProject project : projectFinder.all()) {
|
||||
try {
|
||||
for (String file : getFiles(project)) {
|
||||
String docUri = UriUtil.toUri(new File(file)).toString();
|
||||
symbolHandler.removeSymbols(project, docUri);
|
||||
removeFile(project, docUri);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("{}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void populateIndex() {
|
||||
for (IJavaProject project : projectFinder.all()) {
|
||||
try {
|
||||
initializeProject(project);
|
||||
} catch (Exception e) {
|
||||
log.error("{}", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -19,5 +19,7 @@ import org.springframework.ide.vscode.commons.java.IJavaProject;
|
||||
public interface SymbolHandler {
|
||||
|
||||
void addSymbol(IJavaProject project, String docURI, EnhancedSymbolInformation enhancedSymbol);
|
||||
|
||||
void removeSymbols(IJavaProject project, String docURI);
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
/*******************************************************************************
|
||||
* 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.utils;
|
||||
|
||||
public interface SymbolIndexConfig {
|
||||
|
||||
static class Builder {
|
||||
|
||||
private boolean scanXml = false;
|
||||
|
||||
private boolean scanTestJavaSources = false;
|
||||
|
||||
private String[] xmlScanFoldersGlobs = new String[0];
|
||||
|
||||
private Builder() {
|
||||
|
||||
}
|
||||
|
||||
public Builder scanXml(boolean scanXml) {
|
||||
this.scanXml = scanXml;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder scanTestJavaSources(boolean scanTestJavaSources) {
|
||||
this.scanTestJavaSources = scanTestJavaSources;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder xmlScanFoldersGlobs(String[] xmlScanFoldersGlobs) {
|
||||
this.xmlScanFoldersGlobs = xmlScanFoldersGlobs;
|
||||
return this;
|
||||
}
|
||||
|
||||
public SymbolIndexConfig build() {
|
||||
return new SymbolIndexConfig() {
|
||||
|
||||
@Override
|
||||
public boolean isScanXml() {
|
||||
return scanXml;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isScanTestJavaSources() {
|
||||
return scanTestJavaSources;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String[] getXmlScanFoldersGlobs() {
|
||||
return xmlScanFoldersGlobs;
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
boolean isScanXml();
|
||||
|
||||
boolean isScanTestJavaSources();
|
||||
|
||||
String[] getXmlScanFoldersGlobs();
|
||||
|
||||
static Builder builder() {
|
||||
return new Builder();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -28,6 +28,7 @@ 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.utils.SymbolIndexConfig;
|
||||
import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder;
|
||||
import org.springframework.ide.vscode.commons.util.UriUtil;
|
||||
import org.springframework.ide.vscode.project.harness.BootLanguageServerHarness;
|
||||
@@ -52,7 +53,7 @@ public class SpringIndexerMultiProjectTest {
|
||||
@Before
|
||||
public void setup() throws Exception {
|
||||
harness.intialize(null);
|
||||
indexer.configureIndexer(false);
|
||||
indexer.configureIndexer(SymbolIndexConfig.builder().scanXml(false).build()).get(5, TimeUnit.SECONDS);
|
||||
|
||||
projectUri1 = UriUtil.toUri(new File(ProjectsHarness.class.getResource("/test-projects/test-annotation-indexing-large-multiproject-1/").toURI())).toString();
|
||||
projectFinder.find(new TextDocumentIdentifier(projectUri1)).get();
|
||||
|
||||
@@ -33,6 +33,7 @@ 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.utils.SymbolIndexConfig;
|
||||
import org.springframework.ide.vscode.commons.java.IJavaProject;
|
||||
import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder;
|
||||
import org.springframework.ide.vscode.commons.util.Assert;
|
||||
@@ -59,7 +60,7 @@ public class SpringIndexerTest {
|
||||
@Before
|
||||
public void setup() throws Exception {
|
||||
harness.intialize(null);
|
||||
indexer.configureIndexer(false);
|
||||
indexer.configureIndexer(SymbolIndexConfig.builder().scanXml(false).build()).get(5, TimeUnit.SECONDS);;
|
||||
|
||||
directory = new File(ProjectsHarness.class.getResource("/test-projects/test-annotation-indexing-parent/test-annotation-indexing/").toURI());
|
||||
projectDir = directory.toURI().toString();
|
||||
@@ -92,6 +93,21 @@ public class SpringIndexerTest {
|
||||
docUri = directory.toPath().resolve("src/main/java/org/test/ClassWithDefaultSymbol.java").toUri().toString();
|
||||
assertTrue(containsSymbol(allSymbols, "@Configurable", docUri, 4, 0, 4, 13));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testScanTestJavaSources() throws Exception {
|
||||
indexer.configureIndexer(SymbolIndexConfig.builder().scanTestJavaSources(true).build()).get(1, TimeUnit.SECONDS);
|
||||
|
||||
List<? extends SymbolInformation> allSymbols = indexer.getAllSymbols("");
|
||||
assertEquals(8, allSymbols.size());
|
||||
String docUri = directory.toPath().resolve("src/test/java/demo/ApplicationTests.java").toUri().toString();
|
||||
assertTrue(containsSymbol(allSymbols, "@SpringBootTest", docUri, 8, 0, 8, 15));
|
||||
|
||||
indexer.configureIndexer(SymbolIndexConfig.builder().scanTestJavaSources(false).build()).get(1, TimeUnit.SECONDS);
|
||||
allSymbols = indexer.getAllSymbols("");
|
||||
assertEquals(7, allSymbols.size());
|
||||
assertFalse(containsSymbol(allSymbols, "@SpringBootTest", docUri, 8, 0, 8, 15));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRetrievingSymbolsPerDocument() throws Exception {
|
||||
|
||||
@@ -31,6 +31,7 @@ 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.boot.java.utils.SymbolIndexConfig;
|
||||
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;
|
||||
@@ -56,7 +57,11 @@ public class SpringIndexerXMLProjectTest {
|
||||
@Before
|
||||
public void setup() throws Exception {
|
||||
harness.intialize(null);
|
||||
indexer.configureIndexer(true);
|
||||
indexer.configureIndexer(SymbolIndexConfig.builder()
|
||||
.scanXml(true)
|
||||
.xmlScanFoldersGlobs(new String[] { "**/src/main/**", "**/config" })
|
||||
.build())
|
||||
.get(5, TimeUnit.SECONDS);;
|
||||
|
||||
directory = new File(ProjectsHarness.class.getResource("/test-projects/test-annotation-indexing-xml-project/").toURI());
|
||||
projectDir = directory.toURI().toString();
|
||||
@@ -65,7 +70,7 @@ public class SpringIndexerXMLProjectTest {
|
||||
project = projectFinder.find(new TextDocumentIdentifier(projectDir)).get();
|
||||
|
||||
CompletableFuture<Void> initProject = indexer.waitOperation();
|
||||
initProject.get(5, TimeUnit.SECONDS);
|
||||
initProject.get(50000, TimeUnit.SECONDS);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -111,6 +116,51 @@ public class SpringIndexerXMLProjectTest {
|
||||
assertEquals(1, addon.size());
|
||||
assertEquals("sb", ((BeansSymbolAddOnInformation)addon.get(0)).getBeanID());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testReindexXMLConfig() throws Exception {
|
||||
List<? extends SymbolInformation> allSymbols = indexer.getAllSymbols("");
|
||||
assertEquals(5, allSymbols.size());
|
||||
|
||||
indexer.configureIndexer(SymbolIndexConfig.builder()
|
||||
.scanXml(true)
|
||||
.build())
|
||||
.get(2, TimeUnit.SECONDS);;
|
||||
allSymbols = indexer.getAllSymbols("");
|
||||
assertEquals(0, allSymbols.size());
|
||||
|
||||
indexer.configureIndexer(SymbolIndexConfig.builder()
|
||||
.scanXml(true)
|
||||
.xmlScanFoldersGlobs(new String[] { "**/src/main/**" })
|
||||
.build())
|
||||
.get(2, TimeUnit.SECONDS);
|
||||
allSymbols = indexer.getAllSymbols("");
|
||||
assertEquals(1, allSymbols.size());
|
||||
|
||||
indexer.configureIndexer(SymbolIndexConfig.builder()
|
||||
.scanXml(true)
|
||||
.xmlScanFoldersGlobs(new String[] { "**/config", "**/src/main/**" })
|
||||
.build())
|
||||
.get(2, TimeUnit.SECONDS);
|
||||
allSymbols = indexer.getAllSymbols("");
|
||||
assertEquals(5, allSymbols.size());
|
||||
|
||||
indexer.configureIndexer(SymbolIndexConfig.builder()
|
||||
.scanXml(true)
|
||||
.xmlScanFoldersGlobs(new String[] { "**/config" })
|
||||
.build())
|
||||
.get(2, TimeUnit.SECONDS);
|
||||
allSymbols = indexer.getAllSymbols("");
|
||||
assertEquals(4, allSymbols.size());
|
||||
|
||||
indexer.configureIndexer(SymbolIndexConfig.builder()
|
||||
.scanXml(false)
|
||||
.xmlScanFoldersGlobs(new String[] { "**/config", "**/src/main/**" })
|
||||
.build())
|
||||
.get(2, TimeUnit.SECONDS);
|
||||
allSymbols = indexer.getAllSymbols("");
|
||||
assertEquals(0, allSymbols.size());
|
||||
}
|
||||
|
||||
private boolean containsSymbol(List<? extends SymbolInformation> symbols, String name, String uri, int startLine, int startCHaracter, int endLine, int endCharacter) {
|
||||
for (Iterator<? extends SymbolInformation> iterator = symbols.iterator(); iterator.hasNext();) {
|
||||
|
||||
@@ -25,6 +25,11 @@
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
package demo;
|
||||
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.springframework.boot.test.context.SpringBootTest;
|
||||
import org.springframework.test.context.junit4.SpringRunner;
|
||||
|
||||
@RunWith(SpringRunner.class)
|
||||
@SpringBootTest
|
||||
public class ApplicationTests {
|
||||
|
||||
@Test
|
||||
public void contextLoads() {
|
||||
}
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user