initial version of SpEL syntax validation
This commit is contained in:
@@ -35,6 +35,8 @@ public class BootJavaConfig implements InitializingBean {
|
||||
|
||||
public static final int LIVE_INFORMATION_FETCH_DATA_RETRY_MAX_NO_DEFAULT = 10;
|
||||
public static final int LIVE_INFORMATION_FETCH_DATA_RETRY_DELAY_IN_SECONDS_DEFAULT = 3;
|
||||
|
||||
public static final boolean VALIDAITON_SPEL_EXPRESSIONS_ENABLED_DEFAULT = true;
|
||||
|
||||
|
||||
//TODO: Consider changing this to something that raises Spring application events.
|
||||
@@ -110,6 +112,11 @@ public class BootJavaConfig implements InitializingBean {
|
||||
return enabled != null && enabled.booleanValue();
|
||||
}
|
||||
|
||||
public boolean isSpelExpressionValidationEnabled() {
|
||||
Boolean enabled = settings.getBoolean("boot-java", "validation", "spel", "on");
|
||||
return enabled != null ? enabled.booleanValue() : VALIDAITON_SPEL_EXPRESSIONS_ENABLED_DEFAULT;
|
||||
}
|
||||
|
||||
public boolean areXmlHyperlinksEnabled() {
|
||||
Boolean enabled = settings.getBoolean("boot-java", "support-spring-xml-config", "hyperlinks");
|
||||
return enabled != null && enabled.booleanValue();
|
||||
|
||||
@@ -15,6 +15,7 @@ import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
|
||||
import org.eclipse.lsp4j.CompletionItemKind;
|
||||
@@ -32,6 +33,7 @@ import org.springframework.ide.vscode.boot.java.handlers.BootJavaCompletionEngin
|
||||
import org.springframework.ide.vscode.boot.java.handlers.BootJavaDocumentHighlightEngine;
|
||||
import org.springframework.ide.vscode.boot.java.handlers.BootJavaDocumentSymbolHandler;
|
||||
import org.springframework.ide.vscode.boot.java.handlers.BootJavaHoverProvider;
|
||||
import org.springframework.ide.vscode.boot.java.handlers.BootJavaReconcileEngine;
|
||||
import org.springframework.ide.vscode.boot.java.handlers.BootJavaReferencesHandler;
|
||||
import org.springframework.ide.vscode.boot.java.handlers.BootJavaWorkspaceSymbolHandler;
|
||||
import org.springframework.ide.vscode.boot.java.handlers.CodeLensProvider;
|
||||
@@ -70,6 +72,7 @@ import org.springframework.ide.vscode.commons.languageserver.completion.IComplet
|
||||
import org.springframework.ide.vscode.commons.languageserver.composable.LanguageServerComponents;
|
||||
import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder;
|
||||
import org.springframework.ide.vscode.commons.languageserver.java.ProjectObserver;
|
||||
import org.springframework.ide.vscode.commons.languageserver.reconcile.IReconcileEngine;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.CodeLensHandler;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.DocumentHighlightHandler;
|
||||
import org.springframework.ide.vscode.commons.languageserver.util.HoverHandler;
|
||||
@@ -103,6 +106,8 @@ public class BootJavaLanguageServerComponents implements LanguageServerComponent
|
||||
|
||||
private final SimpleLanguageServer server;
|
||||
private final BootLanguageServerParams serverParams;
|
||||
private final BootJavaConfig config;
|
||||
|
||||
private final SpringPropertyIndexProvider propertyIndexProvider;
|
||||
private final ProjectBasedPropertyIndexProvider adHocPropertyIndexProvider;
|
||||
|
||||
@@ -120,7 +125,6 @@ public class BootJavaLanguageServerComponents implements LanguageServerComponent
|
||||
|
||||
private SpringProcessTracker liveProcessTracker;
|
||||
|
||||
|
||||
public BootJavaLanguageServerComponents(
|
||||
SimpleLanguageServer server,
|
||||
BootLanguageServerParams serverParams,
|
||||
@@ -134,6 +138,7 @@ public class BootJavaLanguageServerComponents implements LanguageServerComponent
|
||||
) {
|
||||
this.server = server;
|
||||
this.serverParams = serverParams;
|
||||
this.config = config;
|
||||
|
||||
projectFinder = serverParams.projectFinder;
|
||||
projectObserver = serverParams.projectObserver;
|
||||
@@ -197,7 +202,7 @@ public class BootJavaLanguageServerComponents implements LanguageServerComponent
|
||||
|
||||
highlightsEngine = createDocumentHighlightEngine(indexer);
|
||||
documents.onDocumentHighlight(highlightsEngine);
|
||||
|
||||
|
||||
config.addListener(ignore -> {
|
||||
log.info("update live process tracker settings - start");
|
||||
|
||||
@@ -245,6 +250,11 @@ public class BootJavaLanguageServerComponents implements LanguageServerComponent
|
||||
public DocumentHighlightHandler getDocumentHighlightHandler() {
|
||||
return highlightsEngine;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<IReconcileEngine> getReconcileEngine() {
|
||||
return Optional.of(new BootJavaReconcileEngine(this, config));
|
||||
}
|
||||
|
||||
private void initialized() {
|
||||
this.liveProcessTracker.start();
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*******************************************************************************
|
||||
* Copyright (c) 2016-2017 Pivotal, Inc.
|
||||
* Copyright (c) 2016, 2020 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
|
||||
@@ -10,8 +10,30 @@
|
||||
*******************************************************************************/
|
||||
package org.springframework.ide.vscode.boot.java.handlers;
|
||||
|
||||
import java.net.URI;
|
||||
|
||||
import org.eclipse.jdt.core.dom.ASTVisitor;
|
||||
import org.eclipse.jdt.core.dom.CompilationUnit;
|
||||
import org.eclipse.jdt.core.dom.Expression;
|
||||
import org.eclipse.jdt.core.dom.ITypeBinding;
|
||||
import org.eclipse.jdt.core.dom.SingleMemberAnnotation;
|
||||
import org.eclipse.jdt.core.dom.StringLiteral;
|
||||
import org.eclipse.lsp4j.TextDocumentIdentifier;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.expression.ParseException;
|
||||
import org.springframework.expression.spel.standard.SpelExpressionParser;
|
||||
import org.springframework.ide.vscode.boot.app.BootJavaConfig;
|
||||
import org.springframework.ide.vscode.boot.java.BootJavaLanguageServerComponents;
|
||||
import org.springframework.ide.vscode.boot.java.value.Constants;
|
||||
import org.springframework.ide.vscode.commons.java.IJavaProject;
|
||||
import org.springframework.ide.vscode.commons.languageserver.java.JavaProjectFinder;
|
||||
import org.springframework.ide.vscode.commons.languageserver.reconcile.IProblemCollector;
|
||||
import org.springframework.ide.vscode.commons.languageserver.reconcile.IReconcileEngine;
|
||||
import org.springframework.ide.vscode.commons.languageserver.reconcile.ProblemSeverity;
|
||||
import org.springframework.ide.vscode.commons.languageserver.reconcile.ProblemTypes;
|
||||
import org.springframework.ide.vscode.commons.languageserver.reconcile.ReconcileProblem;
|
||||
import org.springframework.ide.vscode.commons.languageserver.reconcile.ReconcileProblemImpl;
|
||||
import org.springframework.ide.vscode.commons.util.text.IDocument;
|
||||
|
||||
/**
|
||||
@@ -19,8 +41,104 @@ import org.springframework.ide.vscode.commons.util.text.IDocument;
|
||||
*/
|
||||
public class BootJavaReconcileEngine implements IReconcileEngine {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(BootJavaReconcileEngine.class);
|
||||
|
||||
private final JavaProjectFinder projectFinder;
|
||||
private final BootJavaLanguageServerComponents server;
|
||||
private final BootJavaConfig config;
|
||||
|
||||
public BootJavaReconcileEngine(BootJavaLanguageServerComponents server, BootJavaConfig config) {
|
||||
this.server = server;
|
||||
this.config = config;
|
||||
this.projectFinder = this.server.getProjectFinder();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reconcile(IDocument doc, IProblemCollector problemCollector) {
|
||||
public void reconcile(final IDocument doc, final IProblemCollector problemCollector) {
|
||||
System.out.println("reconcile document: " + doc);
|
||||
|
||||
IJavaProject project = projectFinder.find(new TextDocumentIdentifier(doc.getUri())).orElse(null);
|
||||
URI uri = URI.create(doc.getUri());
|
||||
|
||||
if (project != null) {
|
||||
|
||||
try {
|
||||
problemCollector.beginCollecting();
|
||||
|
||||
server.getCompilationUnitCache().withCompilationUnit(project, uri, cu -> {
|
||||
if (cu != null) {
|
||||
reconcileAST(cu, problemCollector);
|
||||
}
|
||||
|
||||
return null;
|
||||
});
|
||||
}
|
||||
finally {
|
||||
problemCollector.endCollecting();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void reconcileAST(CompilationUnit cu, IProblemCollector problemCollector) {
|
||||
cu.accept(new ASTVisitor() {
|
||||
|
||||
@Override
|
||||
public boolean visit(SingleMemberAnnotation node) {
|
||||
try {
|
||||
visitAnnotation(node, problemCollector);
|
||||
}
|
||||
catch (Exception e) {
|
||||
}
|
||||
return super.visit(node);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected void visitAnnotation(SingleMemberAnnotation node, IProblemCollector problemCollector) {
|
||||
if (!config.isSpelExpressionValidationEnabled()) {
|
||||
return;
|
||||
}
|
||||
|
||||
ITypeBinding typeBinding = node.resolveTypeBinding();
|
||||
|
||||
if (typeBinding != null) {
|
||||
String qname = typeBinding.getQualifiedName();
|
||||
if (Constants.SPRING_VALUE.equals(qname)) {
|
||||
Expression valueExp = node.getValue();
|
||||
|
||||
if (valueExp instanceof StringLiteral) {
|
||||
String value = ((StringLiteral) valueExp).getLiteralValue();
|
||||
if (value != null && value.startsWith("#{") && value.endsWith("}")) {
|
||||
reconcileSpELExpressionValue(value, valueExp, problemCollector);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void reconcileSpELExpressionValue(String value, Expression valueExp, IProblemCollector problemCollector) {
|
||||
String spelExpression = value.substring(2, value.length() - 1);
|
||||
|
||||
if (spelExpression.length() > 0) {
|
||||
SpelExpressionParser parser = new SpelExpressionParser();
|
||||
try {
|
||||
parser.parseExpression(spelExpression);
|
||||
}
|
||||
catch (ParseException e) {
|
||||
String message = e.getSimpleMessage();
|
||||
int position = e.getPosition();
|
||||
|
||||
createProblem(valueExp, message, position, problemCollector);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void createProblem(Expression valueExp, String message, int position, IProblemCollector problemCollector) {
|
||||
int start = valueExp.getStartPosition() + 3 + position;
|
||||
int length = valueExp.getLength() - 5 - position;
|
||||
|
||||
ReconcileProblem problem = new ReconcileProblemImpl(ProblemTypes.create("SpEL Expression Problem", ProblemSeverity.ERROR), message, start, length);
|
||||
problemCollector.accept(problem);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user