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:
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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]);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user