Merge branch 'master' of github.com:spring-projects/sts4

Conflicts:
	headless-services/boot-java-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/ASTUtils.java
This commit is contained in:
Kris De Volder
2017-10-31 14:36:27 -07:00
13 changed files with 419 additions and 104 deletions

View File

@@ -43,6 +43,7 @@ import org.springframework.ide.vscode.boot.java.scope.ScopeCompletionProcessor;
import org.springframework.ide.vscode.boot.java.snippets.JavaSnippet;
import org.springframework.ide.vscode.boot.java.snippets.JavaSnippetContext;
import org.springframework.ide.vscode.boot.java.snippets.JavaSnippetManager;
import org.springframework.ide.vscode.boot.java.utils.CompilationUnitCache;
import org.springframework.ide.vscode.boot.java.utils.SpringIndexer;
import org.springframework.ide.vscode.boot.java.utils.SpringLiveHoverWatchdog;
import org.springframework.ide.vscode.boot.java.value.ValueCompletionProcessor;
@@ -77,6 +78,7 @@ public class BootJavaLanguageServer extends SimpleLanguageServer {
private final SpringLiveHoverWatchdog liveHoverWatchdog;
private final ProjectObserver projectObserver;
private final BootJavaConfig config;
private final CompilationUnitCache cuCache;
private final WordHighlighter testHightlighter = null; //new WordHighlighter("foo");
@@ -88,6 +90,10 @@ public class BootJavaLanguageServer extends SimpleLanguageServer {
this.config = new BootJavaConfig();
projectFinder = serverParams.projectFinder;
projectObserver = serverParams.projectObserver;
cuCache = new CompilationUnitCache(projectFinder, getWorkspaceService().getFileObserver(), projectObserver);
propertyIndexProvider = serverParams.indexProvider;
JavaProjectFinder javaProjectFinder = serverParams.projectFinder;
@@ -126,9 +132,6 @@ public class BootJavaLanguageServer extends SimpleLanguageServer {
documents.onCodeLens(codeLensHandler::createCodeLenses);
documents.onCodeLensResolve(codeLensHandler::resolveCodeLens);
projectFinder = serverParams.projectFinder;
projectObserver = serverParams.projectObserver;
liveHoverWatchdog = new SpringLiveHoverWatchdog(this, hoverInfoProvider, serverParams.runningAppProvider, projectFinder, projectObserver, serverParams.watchDogInterval);
documents.onDidChangeContent(params -> {
TextDocument doc = params.getDocument();
@@ -140,6 +143,14 @@ public class BootJavaLanguageServer extends SimpleLanguageServer {
}
});
documents.onDidClose(doc -> {
if (testHightlighter != null) {
getClient().highlight(new HighlightParams(doc.getId(), testHightlighter.apply(doc)));
} else {
liveHoverWatchdog.unwatchDocument(doc.getUri());
}
});
workspaceService.onDidChangeConfiguraton(settings -> {
config.handleConfigurationChange(settings);
if (config.isBootHintsEnabled()) {
@@ -177,6 +188,7 @@ public class BootJavaLanguageServer extends SimpleLanguageServer {
public CompletableFuture<Object> shutdown() {
this.liveHoverWatchdog.shutdown();
this.indexer.shutdown();
this.cuCache.dispose();
return super.shutdown();
}
@@ -332,4 +344,8 @@ public class BootJavaLanguageServer extends SimpleLanguageServer {
public BootJavaConfig getConfig() {
return config;
}
public CompilationUnitCache getCompilationUnitCache() {
return cuCache;
}
}

View File

@@ -12,7 +12,6 @@ package org.springframework.ide.vscode.boot.java.autowired;
import java.util.Collection;
import java.util.List;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Collectors;
@@ -24,14 +23,13 @@ import org.eclipse.lsp4j.Hover;
import org.eclipse.lsp4j.Range;
import org.eclipse.lsp4j.jsonrpc.messages.Either;
import org.springframework.ide.vscode.boot.java.handlers.HoverProvider;
import org.springframework.ide.vscode.boot.java.livehover.ASTUtils;
import org.springframework.ide.vscode.boot.java.livehover.LiveHoverUtils;
import org.springframework.ide.vscode.boot.java.utils.ASTUtils;
import org.springframework.ide.vscode.commons.boot.app.cli.SpringBootApp;
import org.springframework.ide.vscode.commons.boot.app.cli.livebean.LiveBean;
import org.springframework.ide.vscode.commons.boot.app.cli.livebean.LiveBeansModel;
import org.springframework.ide.vscode.commons.util.BadLocationException;
import org.springframework.ide.vscode.commons.util.Log;
import org.springframework.ide.vscode.commons.util.Optionals;
import org.springframework.ide.vscode.commons.util.StringUtil;
import org.springframework.ide.vscode.commons.util.text.TextDocument;

View File

@@ -10,19 +10,14 @@
*******************************************************************************/
package org.springframework.ide.vscode.boot.java.handlers;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.CompletableFuture;
import java.util.stream.Stream;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.dom.AST;
import org.eclipse.jdt.core.dom.ASTNode;
import org.eclipse.jdt.core.dom.ASTParser;
import org.eclipse.jdt.core.dom.ASTVisitor;
import org.eclipse.jdt.core.dom.Annotation;
import org.eclipse.jdt.core.dom.CompilationUnit;
@@ -37,7 +32,7 @@ import org.eclipse.lsp4j.TextDocumentIdentifier;
import org.eclipse.lsp4j.TextDocumentPositionParams;
import org.eclipse.lsp4j.jsonrpc.messages.Either;
import org.springframework.ide.vscode.boot.java.BootJavaLanguageServer;
import org.springframework.ide.vscode.boot.java.livehover.ASTUtils;
import org.springframework.ide.vscode.boot.java.utils.ASTUtils;
import org.springframework.ide.vscode.commons.boot.app.cli.SpringBootApp;
import org.springframework.ide.vscode.commons.java.IClasspath;
import org.springframework.ide.vscode.commons.java.IJavaProject;
@@ -45,7 +40,6 @@ import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFin
import org.springframework.ide.vscode.commons.languageserver.util.DocumentRegion;
import org.springframework.ide.vscode.commons.languageserver.util.HoverHandler;
import org.springframework.ide.vscode.commons.languageserver.util.SimpleTextDocumentService;
import org.springframework.ide.vscode.commons.util.BadLocationException;
import org.springframework.ide.vscode.commons.util.Log;
import org.springframework.ide.vscode.commons.util.text.IDocument;
import org.springframework.ide.vscode.commons.util.text.TextDocument;
@@ -91,17 +85,15 @@ public class BootJavaHoverProvider implements HoverHandler {
public Range[] getLiveHoverHints(final TextDocument document, final SpringBootApp[] runningBootApps) {
List<Range> result = new ArrayList<>();
getProject(document).ifPresent(project -> {
try {
CompilationUnit cu = parse(document, project);
try {
CompilationUnit cu = server.getCompilationUnitCache().getCompilationUnit(document);
if (cu != null) {
cu.accept(new ASTVisitor() {
@Override
public boolean visit(SingleMemberAnnotation node) {
try {
extractLiveHints(node, document, runningBootApps, result);
}
catch (Exception e) {
} catch (Exception e) {
Log.log(e);
}
@@ -112,8 +104,7 @@ public class BootJavaHoverProvider implements HoverHandler {
public boolean visit(NormalAnnotation node) {
try {
extractLiveHints(node, document, runningBootApps, result);
}
catch (Exception e) {
} catch (Exception e) {
Log.log(e);
}
@@ -124,18 +115,17 @@ public class BootJavaHoverProvider implements HoverHandler {
public boolean visit(MarkerAnnotation node) {
try {
extractLiveHints(node, document, runningBootApps, result);
}
catch (Exception e) {
} catch (Exception e) {
Log.log(e);
}
return super.visit(node);
}
});
} catch (Exception e) {
Log.log(e);
}
});
} catch (Exception e) {
Log.log(e);
}
return result.toArray(new Range[result.size()]);
}
@@ -167,7 +157,7 @@ public class BootJavaHoverProvider implements HoverHandler {
private CompletableFuture<Hover> provideHover(TextDocument document, int offset) throws Exception {
IJavaProject project = getProject(document).orElse(null);
if (project!=null) {
CompilationUnit cu = parse(document, project);
CompilationUnit cu = server.getCompilationUnitCache().getCompilationUnit(document);
ASTNode node = NodeFinder.perform(cu, offset, 0);
if (node != null) {
return provideHoverForAnnotation(node, offset, document, project);
@@ -176,30 +166,6 @@ public class BootJavaHoverProvider implements HoverHandler {
return null;
}
private CompilationUnit parse(TextDocument document, IJavaProject project)
throws Exception, BadLocationException {
ASTParser parser = ASTParser.newParser(AST.JLS8);
Map<String, String> options = JavaCore.getOptions();
JavaCore.setComplianceOptions(JavaCore.VERSION_1_8, options);
parser.setCompilerOptions(options);
parser.setKind(ASTParser.K_COMPILATION_UNIT);
parser.setStatementsRecovery(true);
parser.setBindingsRecovery(true);
parser.setResolveBindings(true);
String[] classpathEntries = getClasspathEntries(project);
String[] sourceEntries = new String[] {};
parser.setEnvironment(classpathEntries, sourceEntries, null, true);
String docURI = document.getUri();
String unitName = docURI.substring(docURI.lastIndexOf("/"));
parser.setUnitName(unitName);
parser.setSource(document.get(0, document.getLength()).toCharArray());
CompilationUnit cu = (CompilationUnit) parser.createAST(null);
return cu;
}
private CompletableFuture<Hover> provideHoverForAnnotation(ASTNode node, int offset, TextDocument doc, IJavaProject project) {
Annotation annotation = null;
@@ -261,14 +227,6 @@ public class BootJavaHoverProvider implements HoverHandler {
return this.projectFinder.find(new TextDocumentIdentifier(doc.getUri()));
}
private String[] getClasspathEntries(IJavaProject project) throws Exception {
IClasspath classpath = project.getClasspath();
Stream<Path> classpathEntries = classpath.getClasspathEntries();
return classpathEntries
.filter(path -> path.toFile().exists())
.map(path -> path.toAbsolutePath().toString()).toArray(String[]::new);
}
private SpringBootApp[] getRunningSpringApps(IJavaProject project) {
try {
return runningAppProvider.getAllRunningSpringApps().toArray(new SpringBootApp[0]);

View File

@@ -24,6 +24,7 @@ import org.eclipse.lsp4j.Hover;
import org.eclipse.lsp4j.Range;
import org.eclipse.lsp4j.jsonrpc.messages.Either;
import org.springframework.ide.vscode.boot.java.handlers.HoverProvider;
import org.springframework.ide.vscode.boot.java.utils.ASTUtils;
import org.springframework.ide.vscode.commons.boot.app.cli.SpringBootApp;
import org.springframework.ide.vscode.commons.boot.app.cli.livebean.LiveBean;
import org.springframework.ide.vscode.commons.boot.app.cli.livebean.LiveBeansModel;

View File

@@ -10,6 +10,8 @@
*******************************************************************************/
package org.springframework.ide.vscode.boot.java.livehover;
import static org.springframework.ide.vscode.boot.java.utils.ASTUtils.*;
import java.util.Collection;
import java.util.List;
import java.util.Optional;
@@ -25,6 +27,7 @@ import org.eclipse.lsp4j.Hover;
import org.eclipse.lsp4j.Range;
import org.eclipse.lsp4j.jsonrpc.messages.Either;
import org.springframework.ide.vscode.boot.java.handlers.HoverProvider;
import org.springframework.ide.vscode.boot.java.utils.ASTUtils;
import org.springframework.ide.vscode.commons.boot.app.cli.SpringBootApp;
import org.springframework.ide.vscode.commons.util.Log;
import org.springframework.ide.vscode.commons.util.text.TextDocument;
@@ -33,8 +36,6 @@ import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableList.Builder;
import com.google.common.collect.ImmutableSet;
import static org.springframework.ide.vscode.boot.java.livehover.ASTUtils.*;
/**
* @author Kris De Volder
*/
@@ -88,7 +89,7 @@ public class ActiveProfilesProvider implements HoverProvider {
annotation.accept(new ASTVisitor() {
@Override
public boolean visit(StringLiteral node) {
String value = node.getLiteralValue();
String value = ASTUtils.getLiteralValue(node);
if (value!=null && allActiveProfiles.contains(value)) {
rangeOf(doc, node).ifPresent(ranges::add);
}

View File

@@ -14,6 +14,7 @@ import java.util.Optional;
import org.eclipse.jdt.core.dom.Annotation;
import org.eclipse.jdt.core.dom.MethodDeclaration;
import org.springframework.ide.vscode.boot.java.utils.ASTUtils;
import org.springframework.ide.vscode.commons.boot.app.cli.livebean.LiveBean;
import org.springframework.ide.vscode.commons.util.Optionals;

View File

@@ -18,6 +18,7 @@ import org.eclipse.jdt.core.dom.MarkerAnnotation;
import org.eclipse.jdt.core.dom.MethodDeclaration;
import org.eclipse.jdt.core.dom.TypeDeclaration;
import org.springframework.ide.vscode.boot.java.autowired.Constants;
import org.springframework.ide.vscode.boot.java.utils.ASTUtils;
import org.springframework.ide.vscode.commons.boot.app.cli.livebean.LiveBean;
import org.springframework.ide.vscode.commons.boot.app.cli.livebean.LiveBeansModel;
import org.springframework.ide.vscode.commons.util.StringUtil;

View File

@@ -20,21 +20,18 @@ import java.util.stream.Stream;
import org.eclipse.jdt.core.dom.ASTNode;
import org.eclipse.jdt.core.dom.Annotation;
import org.eclipse.jdt.core.dom.ArrayInitializer;
import org.eclipse.jdt.core.dom.Expression;
import org.eclipse.jdt.core.dom.ITypeBinding;
import org.eclipse.jdt.core.dom.MemberValuePair;
import org.eclipse.jdt.core.dom.MethodDeclaration;
import org.eclipse.jdt.core.dom.NormalAnnotation;
import org.eclipse.jdt.core.dom.QualifiedName;
import org.eclipse.jdt.core.dom.SimpleName;
import org.eclipse.jdt.core.dom.SingleMemberAnnotation;
import org.eclipse.jdt.core.dom.StringLiteral;
import org.eclipse.jdt.core.dom.TypeDeclaration;
import org.eclipse.lsp4j.Location;
import org.eclipse.lsp4j.SymbolInformation;
import org.eclipse.lsp4j.SymbolKind;
import org.springframework.ide.vscode.boot.java.handlers.SymbolProvider;
import org.springframework.ide.vscode.boot.java.utils.ASTUtils;
import org.springframework.ide.vscode.commons.util.text.TextDocument;
/**
@@ -81,7 +78,7 @@ public class RequestMappingSymbolProvider implements SymbolProvider {
String valueName = pair.getName().getIdentifier();
if (valueName != null && valueName.equals("method")) {
Expression expression = pair.getValue();
methods = getExpressionValueAsArray(expression);
methods = ASTUtils.getExpressionValueAsArray(expression);
break;
}
}
@@ -111,14 +108,14 @@ public class RequestMappingSymbolProvider implements SymbolProvider {
String valueName = pair.getName().getIdentifier();
if (valueName != null && (valueName.equals("value") || valueName.equals("path"))) {
Expression expression = pair.getValue();
return getExpressionValueAsArray(expression);
return ASTUtils.getExpressionValueAsArray(expression);
}
}
}
} else if (node.isSingleMemberAnnotation()) {
SingleMemberAnnotation singleNode = (SingleMemberAnnotation) node;
Expression expression = singleNode.getValue();
return getExpressionValueAsArray(expression);
return ASTUtils.getExpressionValueAsArray(expression);
}
return null;
@@ -173,31 +170,4 @@ public class RequestMappingSymbolProvider implements SymbolProvider {
return null;
}
private static String getExpressionValueAsString(Expression exp) {
if (exp instanceof StringLiteral) {
return ((StringLiteral) exp).getLiteralValue();
} else if (exp instanceof QualifiedName) {
return getExpressionValueAsString(((QualifiedName) exp).getName());
} else if (exp instanceof SimpleName) {
return ((SimpleName) exp).getIdentifier();
} else {
return null;
}
}
@SuppressWarnings("unchecked")
private static String[] getExpressionValueAsArray(Expression exp) {
if (exp instanceof ArrayInitializer) {
ArrayInitializer array = (ArrayInitializer) exp;
return ((List<Expression>) array.expressions()).stream().map(e -> getExpressionValueAsString(e))
.filter(Objects::nonNull).toArray(String[]::new);
} else {
String rm = getExpressionValueAsString(exp);
if (rm != null) {
return new String[] { rm };
}
}
return null;
}
}

View File

@@ -8,29 +8,28 @@
* Contributors:
* Pivotal, Inc. - initial API and implementation
*******************************************************************************/
package org.springframework.ide.vscode.boot.java.livehover;
package org.springframework.ide.vscode.boot.java.utils;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import org.eclipse.jdt.core.dom.ASTNode;
import org.eclipse.jdt.core.dom.Annotation;
import org.eclipse.jdt.core.dom.ArrayInitializer;
import org.eclipse.jdt.core.dom.Expression;
import org.eclipse.jdt.core.dom.ITypeBinding;
import org.eclipse.jdt.core.dom.MemberValuePair;
import org.eclipse.jdt.core.dom.MethodDeclaration;
import org.eclipse.jdt.core.dom.NormalAnnotation;
import org.eclipse.jdt.core.dom.QualifiedName;
import org.eclipse.jdt.core.dom.SimpleName;
import org.eclipse.jdt.core.dom.SingleMemberAnnotation;
import org.eclipse.jdt.core.dom.StringLiteral;
import org.eclipse.jdt.core.dom.TypeDeclaration;
import org.eclipse.lsp4j.Range;
import org.springframework.ide.vscode.commons.boot.app.cli.livebean.LiveBean;
import org.springframework.ide.vscode.commons.languageserver.util.DocumentRegion;
import org.springframework.ide.vscode.commons.util.BadLocationException;
import org.springframework.ide.vscode.commons.util.Log;
import org.springframework.ide.vscode.commons.util.StringUtil;
import org.springframework.ide.vscode.commons.util.text.TextDocument;
public class ASTUtils {
@@ -87,7 +86,7 @@ public class ASTUtils {
*/
public static Optional<String> getFirstString(Expression exp) {
if (exp instanceof StringLiteral) {
return Optional.ofNullable(((StringLiteral) exp).getLiteralValue());
return Optional.ofNullable(getLiteralValue((StringLiteral) exp));
} else if (exp instanceof ArrayInitializer) {
ArrayInitializer array = (ArrayInitializer) exp;
Object objs = array.getStructuralProperty(ArrayInitializer.EXPRESSIONS_PROPERTY);
@@ -143,4 +142,38 @@ public class ASTUtils {
return null;
}
public static String getLiteralValue(StringLiteral node) {
synchronized (node.getAST()) {
return node.getLiteralValue();
}
}
public static String getExpressionValueAsString(Expression exp) {
if (exp instanceof StringLiteral) {
return getLiteralValue((StringLiteral) exp);
} else if (exp instanceof QualifiedName) {
return getExpressionValueAsString(((QualifiedName) exp).getName());
} else if (exp instanceof SimpleName) {
return ((SimpleName) exp).getIdentifier();
} else {
return null;
}
}
@SuppressWarnings("unchecked")
public
static String[] getExpressionValueAsArray(Expression exp) {
if (exp instanceof ArrayInitializer) {
ArrayInitializer array = (ArrayInitializer) exp;
return ((List<Expression>) array.expressions()).stream().map(e -> getExpressionValueAsString(e))
.filter(Objects::nonNull).toArray(String[]::new);
} else {
String rm = getExpressionValueAsString(exp);
if (rm != null) {
return new String[] { rm };
}
}
return null;
}
}

View File

@@ -0,0 +1,174 @@
package org.springframework.ide.vscode.boot.java.utils;
import java.net.URI;
import java.nio.file.Path;
import java.util.Collections;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock;
import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock;
import java.util.stream.Stream;
import org.eclipse.jdt.core.JavaCore;
import org.eclipse.jdt.core.dom.AST;
import org.eclipse.jdt.core.dom.ASTParser;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.springframework.ide.vscode.commons.java.IClasspath;
import org.springframework.ide.vscode.commons.java.IJavaProject;
import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder;
import org.springframework.ide.vscode.commons.languageserver.java.ProjectObserver;
import org.springframework.ide.vscode.commons.util.BadLocationException;
import org.springframework.ide.vscode.commons.util.FileObserver;
import org.springframework.ide.vscode.commons.util.text.TextDocument;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
public final class CompilationUnitCache {
private static final String GLOB_ALL_JAVA_FILES = "**/*.java";
private JavaProjectFinder projectFinder;
private FileObserver fileObserver;
private ProjectObserver projectObserver;
private Cache<URI, CompilationUnit> uriToCu;
private Cache<IJavaProject, Set<URI>> projectToDocs;
private String fileChangeSubscription;
private String fileDeletedSubscription;
private ProjectObserver.Listener projectListener;
private ReadLock readLock;
private WriteLock writeLock;
public CompilationUnitCache(JavaProjectFinder projectFinder, FileObserver fileObserver, ProjectObserver projectObserver) {
this.projectFinder = projectFinder;
this.fileObserver = fileObserver;
this.projectObserver = projectObserver;
projectListener = new CUProjectListener();
uriToCu = CacheBuilder.newBuilder().build();
projectToDocs = CacheBuilder.newBuilder().build();
if (this.fileObserver != null) {
fileChangeSubscription = this.fileObserver.onFileChanged(Collections.singletonList(GLOB_ALL_JAVA_FILES), (uri) -> invalidateCuForJavaFile(uri));
fileDeletedSubscription = this.fileObserver.onFileDeleted(Collections.singletonList(GLOB_ALL_JAVA_FILES), (uri) -> invalidateCuForJavaFile(uri));
}
if (this.projectObserver != null) {
this.projectObserver.addListener(projectListener);
}
ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
readLock = lock.readLock();
writeLock = lock.writeLock();
}
public void dispose() {
if (fileObserver != null) {
fileObserver.unsubscribe(fileChangeSubscription);
fileObserver.unsubscribe(fileDeletedSubscription);
}
if (projectObserver != null) {
projectObserver.removeListener(projectListener);
}
}
public CompilationUnit getCompilationUnit(TextDocument document) throws Exception {
URI uri = URI.create(document.getUri());
readLock.lock();
try {
return uriToCu.get(uri, () -> parse(document));
} finally {
readLock.unlock();
}
}
private void invalidateCuForJavaFile(String uriStr) {
URI uri = URI.create(uriStr);
writeLock.lock();
try {
uriToCu.invalidate(uri);
} finally {
writeLock.unlock();
}
}
public static CompilationUnit parse(TextDocument document, IJavaProject project) throws Exception {
ASTParser parser = ASTParser.newParser(AST.JLS8);
Map<String, String> options = JavaCore.getOptions();
JavaCore.setComplianceOptions(JavaCore.VERSION_1_8, options);
parser.setCompilerOptions(options);
parser.setKind(ASTParser.K_COMPILATION_UNIT);
parser.setStatementsRecovery(true);
parser.setBindingsRecovery(true);
parser.setResolveBindings(true);
String[] classpathEntries = getClasspathEntries(document, project);
String[] sourceEntries = new String[] {};
parser.setEnvironment(classpathEntries, sourceEntries, null, true);
String docURI = document.getUri();
String unitName = docURI.substring(docURI.lastIndexOf("/"));
parser.setUnitName(unitName);
parser.setSource(document.get(0, document.getLength()).toCharArray());
CompilationUnit cu = (CompilationUnit) parser.createAST(null);
return cu;
}
private CompilationUnit parse(TextDocument document)
throws Exception, BadLocationException {
IJavaProject project = projectFinder.find(document.getId()).orElse(null);
CompilationUnit cu = parse(document, project);
if (project != null) {
projectToDocs.get(project, () -> new HashSet<>()).add(URI.create(document.getUri()));
}
return cu;
}
private static String[] getClasspathEntries(TextDocument document, IJavaProject project) throws Exception {
if (project == null) {
return new String[0];
} else {
IClasspath classpath = project.getClasspath();
Stream<Path> classpathEntries = classpath.getClasspathEntries();
return classpathEntries
.filter(path -> path.toFile().exists())
.map(path -> path.toAbsolutePath().toString()).toArray(String[]::new);
}
}
private void invalidateProject(IJavaProject project) {
Set<URI> docUris = projectToDocs.getIfPresent(project);
if (docUris != null) {
writeLock.lock();
try {
uriToCu.invalidateAll(docUris);
projectToDocs.invalidate(project);
} finally {
writeLock.unlock();
}
}
}
private class CUProjectListener implements ProjectObserver.Listener {
@Override
public void created(IJavaProject project) {
}
@Override
public void changed(IJavaProject project) {
invalidateProject(project);
}
@Override
public void deleted(IJavaProject project) {
invalidateProject(project);
}
}
}

View File

@@ -0,0 +1,156 @@
/*******************************************************************************
* 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.utils.test;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import java.io.File;
import java.net.URI;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import org.eclipse.jdt.core.dom.CompilationUnit;
import org.junit.Before;
import org.junit.Test;
import org.springframework.ide.vscode.boot.java.BootJavaLanguageServer;
import org.springframework.ide.vscode.commons.maven.MavenCore;
import org.springframework.ide.vscode.commons.util.text.LanguageId;
import org.springframework.ide.vscode.commons.util.text.TextDocument;
import org.springframework.ide.vscode.languageserver.testharness.LanguageServerHarness;
import org.springframework.ide.vscode.project.harness.BootLanguageServerHarness;
import org.springframework.ide.vscode.project.harness.ProjectsHarness;
/**
* CU Cache tests
*
* @author Alex Boyko
*
*/
public class CompilationUnitCacheTest {
private LanguageServerHarness<BootJavaLanguageServer> harness;
@Before
public void setup() throws Exception {
harness = BootLanguageServerHarness.builder().build();
}
@Test
public void cu_cached() throws Exception {
harness.intialize(null);
TextDocument doc = new TextDocument(harness.createTempUri(), LanguageId.JAVA, 0, "package my.package\n" +
"\n" +
"public class SomeClass {\n" +
"\n" +
"}\n");
CompilationUnit cu = harness.getServer().getCompilationUnitCache().getCompilationUnit(doc);
assertNotNull(cu);
CompilationUnit cuAnother = harness.getServer().getCompilationUnitCache().getCompilationUnit(doc);
assertTrue(cu == cuAnother);
}
@Test
public void cu_cache_invalidated_by_file_change() throws Exception {
harness.intialize(null);
TextDocument doc = new TextDocument(harness.createTempUri(), LanguageId.JAVA, 0, "package my.package\n" +
"\n" +
"public class SomeClass {\n" +
"\n" +
"}\n");
CompilationUnit cu = harness.getServer().getCompilationUnitCache().getCompilationUnit(doc);
assertNotNull(cu);
harness.changeFile(doc.getUri());
CompilationUnit cuAnother = harness.getServer().getCompilationUnitCache().getCompilationUnit(doc);
assertNotNull(cuAnother);
assertFalse(cu == cuAnother);
CompilationUnit cuYetAnother = harness.getServer().getCompilationUnitCache().getCompilationUnit(doc);
assertTrue(cuAnother == cuYetAnother);
}
@Test
public void cu_cache_invalidated_by_file_removal() throws Exception {
harness.intialize(null);
TextDocument doc = new TextDocument(harness.createTempUri(), LanguageId.JAVA, 0, "package my.package\n" +
"\n" +
"public class SomeClass {\n" +
"\n" +
"}\n");
CompilationUnit cu = harness.getServer().getCompilationUnitCache().getCompilationUnit(doc);
assertNotNull(cu);
harness.deleteFile(doc.getUri());
CompilationUnit cuAnother = harness.getServer().getCompilationUnitCache().getCompilationUnit(doc);
assertNotNull(cuAnother);
assertFalse(cu == cuAnother);
CompilationUnit cuYetAnother = harness.getServer().getCompilationUnitCache().getCompilationUnit(doc);
assertTrue(cuAnother == cuYetAnother);
}
@Test
public void cu_cache_invalidated_by_project_change() throws Exception {
File directory = new File(
ProjectsHarness.class.getResource("/test-projects/test-request-mapping-live-hover/").toURI());
String docUri = "file://" +directory.getAbsolutePath() + "/src/main/java/example/HelloWorldController.java";
harness.intialize(directory);
URI fileUri = new URI(docUri);
Path path = Paths.get(fileUri);
String content = new String(Files.readAllBytes(path));
TextDocument document = new TextDocument(docUri, LanguageId.JAVA, 0, content);
CompilationUnit cu = harness.getServer().getCompilationUnitCache().getCompilationUnit(document);
assertNotNull(cu);
CompilationUnit cuAnother = harness.getServer().getCompilationUnitCache().getCompilationUnit(document);
assertTrue(cu == cuAnother);
harness.changeFile(directory.toPath().resolve(MavenCore.POM_XML).toUri().toString());
cuAnother = harness.getServer().getCompilationUnitCache().getCompilationUnit(document);
assertNotNull(cuAnother);
assertFalse(cu == cuAnother);
}
@Test
public void cu_cache_invalidated_by_project_deletion() throws Exception {
File directory = new File(
ProjectsHarness.class.getResource("/test-projects/test-request-mapping-live-hover/").toURI());
String docUri = "file://" +directory.getAbsolutePath() + "/src/main/java/example/HelloWorldController.java";
harness.intialize(directory);
URI fileUri = new URI(docUri);
Path path = Paths.get(fileUri);
String content = new String(Files.readAllBytes(path));
TextDocument document = new TextDocument(docUri, LanguageId.JAVA, 0, content);
CompilationUnit cu = harness.getServer().getCompilationUnitCache().getCompilationUnit(document);
assertNotNull(cu);
CompilationUnit cuAnother = harness.getServer().getCompilationUnitCache().getCompilationUnit(document);
assertTrue(cu == cuAnother);
harness.deleteFile(directory.toPath().resolve(MavenCore.POM_XML).toUri().toString());
cuAnother = harness.getServer().getCompilationUnitCache().getCompilationUnit(document);
assertNotNull(cuAnother);
assertFalse(cu == cuAnother);
}
}