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/conditionals/ConditionalsLiveHoverProvider.java
This commit is contained in:
@@ -79,6 +79,26 @@
|
||||
<category name="Uncategorized"/>
|
||||
</bundle>
|
||||
|
||||
<bundle id="org.springframework.tooling.ls.eclipse.gotosymbol">
|
||||
<category name="Uncategorized"/>
|
||||
</bundle>
|
||||
|
||||
<bundle id="org.springsource.ide.eclipse.commons.core">
|
||||
<category name="Uncategorized"/>
|
||||
</bundle>
|
||||
|
||||
<bundle id="org.springsource.ide.eclipse.commons.livexp">
|
||||
<category name="Uncategorized"/>
|
||||
</bundle>
|
||||
|
||||
<bundle id="io.projectreactor.reactor-core">
|
||||
<category name="Uncategorized"/>
|
||||
</bundle>
|
||||
|
||||
<bundle id="org.reactivestreams.reactive-streams">
|
||||
<category name="Uncategorized"/>
|
||||
</bundle>
|
||||
|
||||
<feature id="tm-feature">
|
||||
<category name="Uncategorized"/>
|
||||
</feature>
|
||||
|
||||
@@ -113,16 +113,16 @@
|
||||
<layout>p2</layout>
|
||||
<url>http://download.eclipse.org/releases/oxygen/</url>
|
||||
</repository>
|
||||
<repository>
|
||||
<!-- <repository>
|
||||
<id>staging</id>
|
||||
<layout>p2</layout>
|
||||
<url>http://download.eclipse.org/staging/oxygen/</url>
|
||||
</repository>
|
||||
<repository>
|
||||
</repository> -->
|
||||
<!-- <repository>
|
||||
<id>platform-m-build</id>
|
||||
<layout>p2</layout>
|
||||
<url>http://download.eclipse.org/eclipse/updates/4.7-M-builds</url>
|
||||
</repository>
|
||||
</repository> -->
|
||||
<repository>
|
||||
<id>latest-m2e</id>
|
||||
<layout>p2</layout>
|
||||
|
||||
@@ -8,6 +8,7 @@
|
||||
<requires>
|
||||
<import plugin="org.eclipse.ui.genericeditor"/>
|
||||
<import plugin="org.eclipse.lsp4e"/>
|
||||
<import plugin="org.springframework.tooling.ls.eclipse.gotosymbol"/>
|
||||
</requires>
|
||||
|
||||
<plugin
|
||||
@@ -18,12 +19,4 @@
|
||||
unpack="false">
|
||||
</plugin>
|
||||
|
||||
<plugin
|
||||
id="org.springframework.tooling.ls.eclipse.gotosymbol"
|
||||
download-size="0"
|
||||
install-size="0"
|
||||
version="0.0.0"
|
||||
unpack="false">
|
||||
</plugin>
|
||||
|
||||
</feature>
|
||||
|
||||
@@ -12,11 +12,11 @@ Require-Bundle: org.eclipse.ui,
|
||||
org.eclipse.core.filebuffers,
|
||||
org.eclipse.ui.navigator,
|
||||
org.eclipse.equinox.registry,
|
||||
org.springsource.ide.eclipse.commons.livexp,
|
||||
org.springsource.ide.eclipse.commons.livexp;bundle-version="3.9.1",
|
||||
com.google.guava,
|
||||
org.eclipse.core.jobs,
|
||||
org.eclipse.core.runtime;bundle-version="3.13.0",
|
||||
org.springsource.ide.eclipse.commons.core
|
||||
org.springsource.ide.eclipse.commons.core;bundle-version="3.9.1"
|
||||
Bundle-RequiredExecutionEnvironment: JavaSE-1.8
|
||||
Bundle-Activator: org.springframework.tooling.ls.eclipse.gotosymbol.GotoSymbolPlugin
|
||||
Bundle-ActivationPolicy: lazy
|
||||
|
||||
@@ -14,9 +14,13 @@ package org.springframework.tooling.ls.eclipse.gotosymbol.dialogs;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import org.eclipse.core.resources.IMarker;
|
||||
import org.eclipse.core.resources.IResource;
|
||||
import org.eclipse.core.runtime.CoreException;
|
||||
import org.eclipse.jface.dialogs.IDialogSettings;
|
||||
import org.eclipse.jface.dialogs.PopupDialog;
|
||||
import org.eclipse.jface.layout.GridDataFactory;
|
||||
import org.eclipse.jface.text.BadLocationException;
|
||||
import org.eclipse.jface.viewers.ISelection;
|
||||
import org.eclipse.jface.viewers.IStructuredSelection;
|
||||
import org.eclipse.jface.viewers.ITreeContentProvider;
|
||||
@@ -72,6 +76,21 @@ public class GotoSymbolDialog extends PopupDialog {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private static class GotoSymbolsLabelProvider extends SymbolsLabelProvider {
|
||||
@Override
|
||||
protected int getMaxSeverity(IResource resource, SymbolInformation symbolInformation)
|
||||
throws CoreException, BadLocationException {
|
||||
int maxSeverity = -1;
|
||||
for (IMarker marker : resource.findMarkers(IMarker.PROBLEM, true, IResource.DEPTH_ZERO)) {
|
||||
int offset = marker.getAttribute(IMarker.CHAR_START, -1);
|
||||
if (offset != -1) {
|
||||
maxSeverity = Math.max(maxSeverity, marker.getAttribute(IMarker.SEVERITY, -1));
|
||||
}
|
||||
}
|
||||
return maxSeverity;
|
||||
}
|
||||
}
|
||||
|
||||
private GotoSymbolDialogModel model;
|
||||
private List<Disposable> disposables = new ArrayList<>();
|
||||
@@ -222,7 +241,7 @@ public class GotoSymbolDialog extends PopupDialog {
|
||||
TreeViewer viewer = new TreeViewer(dialogArea, SWT.SINGLE);
|
||||
GridDataFactory.fillDefaults().grab(true, true).applyTo(viewer.getControl());
|
||||
viewer.setContentProvider(new SymbolsContentProvider());
|
||||
viewer.setLabelProvider(new SymbolsLabelProvider());
|
||||
viewer.setLabelProvider(new GotoSymbolsLabelProvider());
|
||||
viewer.setUseHashlookup(true);
|
||||
disposables.add(model.getSymbols().onChange(UIValueListener.from((e, v) -> {
|
||||
viewer.refresh();
|
||||
|
||||
@@ -32,6 +32,26 @@
|
||||
<category name="deps"/>
|
||||
</bundle>
|
||||
|
||||
<bundle id="org.springframework.tooling.ls.eclipse.gotosymbol">
|
||||
<category name="deps"/>
|
||||
</bundle>
|
||||
|
||||
<bundle id="org.springsource.ide.eclipse.commons.core">
|
||||
<category name="deps"/>
|
||||
</bundle>
|
||||
|
||||
<bundle id="org.springsource.ide.eclipse.commons.livexp">
|
||||
<category name="deps"/>
|
||||
</bundle>
|
||||
|
||||
<bundle id="io.projectreactor.reactor-core">
|
||||
<category name="deps"/>
|
||||
</bundle>
|
||||
|
||||
<bundle id="org.reactivestreams.reactive-streams">
|
||||
<category name="deps"/>
|
||||
</bundle>
|
||||
|
||||
<feature id="tm-feature">
|
||||
<category name="deps"/>
|
||||
</feature>
|
||||
|
||||
@@ -20,4 +20,31 @@ public class Annotations {
|
||||
public static final String PROFILE = "org.springframework.context.annotation.Profile";
|
||||
public static final String COMPONENT = "org.springframework.stereotype.Component";
|
||||
public static final String AUTOWIRED = "org.springframework.beans.factory.annotation.Autowired";
|
||||
|
||||
public static final String SPRING_REQUEST_MAPPING = "org.springframework.web.bind.annotation.RequestMapping";
|
||||
public static final String SPRING_GET_MAPPING = "org.springframework.web.bind.annotation.GetMapping";
|
||||
public static final String SPRING_POST_MAPPING = "org.springframework.web.bind.annotation.PostMapping";
|
||||
public static final String SPRING_PUT_MAPPING = "org.springframework.web.bind.annotation.PutMapping";
|
||||
public static final String SPRING_DELETE_MAPPING = "org.springframework.web.bind.annotation.DeleteMapping";
|
||||
public static final String SPRING_PATCH_MAPPING = "org.springframework.web.bind.annotation.PatchMapping";
|
||||
|
||||
public static final String CONDITIONAL = "org.springframework.context.annotation.Conditional";
|
||||
public static final String CONDITIONAL_ON_BEAN = "org.springframework.boot.autoconfigure.condition.ConditionalOnBean";
|
||||
public static final String CONDITIONAL_ON_MISSING_BEAN = "org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean";
|
||||
public static final String CONDITIONAL_ON_PROPERTY = "org.springframework.boot.autoconfigure.condition.ConditionalOnProperty";
|
||||
public static final String CONDITIONAL_ON_RESOURCE = "org.springframework.boot.autoconfigure.condition.ConditionalOnResource";
|
||||
public static final String CONDITIONAL_ON_CLASS = "org.springframework.boot.autoconfigure.condition.ConditionalOnClass";
|
||||
public static final String CONDITIONAL_ON_MISSING_CLASS = "org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass";
|
||||
public static final String CONDITIONAL_ON_CLOUD_PLATFORM = "org.springframework.boot.autoconfigure.condition.ConditionalOnCloudPlatform";
|
||||
public static final String CONDITIONAL_ON_WEB_APPLICATION = "org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication";
|
||||
public static final String CONDITIONAL_ON_NOT_WEB_APPLICATION = "org.springframework.boot.autoconfigure.condition.ConditionalOnNotWebApplication";
|
||||
public static final String CONDITIONAL_ON_ENABLED_INFO_CONTRIBUTOR = "org.springframework.boot.actuate.autoconfigure.ConditionalOnEnabledInfoContributor";
|
||||
public static final String CONDITIONAL_ON_ENABLED_RESOURCE_CHAIN = "org.springframework.boot.autoconfigure.web.ConditionalOnEnabledResourceChain";
|
||||
public static final String CONDITIONAL_ON_ENABLED_ENDPOINT = "org.springframework.boot.actuate.condition.ConditionalOnEnabledEndpoint";
|
||||
public static final String CONDITIONAL_ON_ENABLED_HEALTH_INDICATOR = "org.springframework.boot.actuate.autoconfigure.ConditionalOnEnabledHealthIndicator";
|
||||
public static final String CONDITIONAL_ON_EXPRESSION = "org.springframework.boot.autoconfigure.condition.ConditionalOnExpression";
|
||||
public static final String CONDITIONAL_ON_JAVA = "org.springframework.boot.autoconfigure.condition.ConditionalOnJava";
|
||||
public static final String CONDITIONAL_ON_JNDI = "org.springframework.boot.autoconfigure.condition.ConditionalOnJndi";
|
||||
public static final String CONDITIONAL_ON_SINGLE_CANDIDATE = "org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate";
|
||||
|
||||
}
|
||||
|
||||
@@ -245,17 +245,17 @@ public class BootJavaLanguageServer extends SimpleLanguageServer {
|
||||
|
||||
providers.put(org.springframework.ide.vscode.boot.java.value.Constants.SPRING_VALUE, new ValueHoverProvider());
|
||||
|
||||
providers.put(org.springframework.ide.vscode.boot.java.requestmapping.Constants.SPRING_REQUEST_MAPPING,
|
||||
providers.put(Annotations.SPRING_REQUEST_MAPPING,
|
||||
new RequestMappingHoverProvider());
|
||||
providers.put(org.springframework.ide.vscode.boot.java.requestmapping.Constants.SPRING_GET_MAPPING,
|
||||
providers.put(Annotations.SPRING_GET_MAPPING,
|
||||
new RequestMappingHoverProvider());
|
||||
providers.put(org.springframework.ide.vscode.boot.java.requestmapping.Constants.SPRING_POST_MAPPING,
|
||||
providers.put(Annotations.SPRING_POST_MAPPING,
|
||||
new RequestMappingHoverProvider());
|
||||
providers.put(org.springframework.ide.vscode.boot.java.requestmapping.Constants.SPRING_PUT_MAPPING,
|
||||
providers.put(Annotations.SPRING_PUT_MAPPING,
|
||||
new RequestMappingHoverProvider());
|
||||
providers.put(org.springframework.ide.vscode.boot.java.requestmapping.Constants.SPRING_DELETE_MAPPING,
|
||||
providers.put(Annotations.SPRING_DELETE_MAPPING,
|
||||
new RequestMappingHoverProvider());
|
||||
providers.put(org.springframework.ide.vscode.boot.java.requestmapping.Constants.SPRING_PATCH_MAPPING,
|
||||
providers.put(Annotations.SPRING_PATCH_MAPPING,
|
||||
new RequestMappingHoverProvider());
|
||||
providers.put(Annotations.PROFILE, new ActiveProfilesProvider());
|
||||
|
||||
@@ -263,45 +263,41 @@ public class BootJavaLanguageServer extends SimpleLanguageServer {
|
||||
providers.put(Annotations.COMPONENT, new ComponentInjectionsHoverProvider());
|
||||
providers.put(Annotations.BEAN, new BeanInjectedIntoHoverProvider());
|
||||
|
||||
providers.put(org.springframework.ide.vscode.boot.java.conditionals.Constants.CONDITIONAL,
|
||||
providers.put(Annotations.CONDITIONAL,
|
||||
new ConditionalsLiveHoverProvider());
|
||||
providers.put(org.springframework.ide.vscode.boot.java.conditionals.Constants.CONDITIONAL_ON_BEAN,
|
||||
providers.put(Annotations.CONDITIONAL_ON_BEAN,
|
||||
new ConditionalsLiveHoverProvider());
|
||||
providers.put(org.springframework.ide.vscode.boot.java.conditionals.Constants.CONDITIONAL_ON_MISSING_BEAN,
|
||||
providers.put(Annotations.CONDITIONAL_ON_MISSING_BEAN,
|
||||
new ConditionalsLiveHoverProvider());
|
||||
providers.put(org.springframework.ide.vscode.boot.java.conditionals.Constants.CONDITIONAL_ON_PROPERTY,
|
||||
providers.put(Annotations.CONDITIONAL_ON_PROPERTY,
|
||||
new ConditionalsLiveHoverProvider());
|
||||
providers.put(org.springframework.ide.vscode.boot.java.conditionals.Constants.CONDITIONAL_ON_RESOURCE,
|
||||
providers.put(Annotations.CONDITIONAL_ON_RESOURCE,
|
||||
new ConditionalsLiveHoverProvider());
|
||||
providers.put(org.springframework.ide.vscode.boot.java.conditionals.Constants.CONDITIONAL_ON_CLASS,
|
||||
providers.put(Annotations.CONDITIONAL_ON_CLASS,
|
||||
new ConditionalsLiveHoverProvider());
|
||||
providers.put(org.springframework.ide.vscode.boot.java.conditionals.Constants.CONDITIONAL_ON_MISSING_CLASS,
|
||||
providers.put(Annotations.CONDITIONAL_ON_MISSING_CLASS,
|
||||
new ConditionalsLiveHoverProvider());
|
||||
providers.put(org.springframework.ide.vscode.boot.java.conditionals.Constants.CONDITIONAL_ON_CLOUD_PLATFORM,
|
||||
providers.put(Annotations.CONDITIONAL_ON_CLOUD_PLATFORM,
|
||||
new ConditionalsLiveHoverProvider());
|
||||
providers.put(org.springframework.ide.vscode.boot.java.conditionals.Constants.CONDITIONAL_ON_WEB_APPLICATION,
|
||||
providers.put(Annotations.CONDITIONAL_ON_WEB_APPLICATION,
|
||||
new ConditionalsLiveHoverProvider());
|
||||
providers.put(
|
||||
org.springframework.ide.vscode.boot.java.conditionals.Constants.CONDITIONAL_ON_NOT_WEB_APPLICATION,
|
||||
providers.put(Annotations.CONDITIONAL_ON_NOT_WEB_APPLICATION,
|
||||
new ConditionalsLiveHoverProvider());
|
||||
providers.put(
|
||||
org.springframework.ide.vscode.boot.java.conditionals.Constants.CONDITIONAL_ON_ENABLED_INFO_CONTRIBUTOR,
|
||||
providers.put(Annotations.CONDITIONAL_ON_ENABLED_INFO_CONTRIBUTOR,
|
||||
new ConditionalsLiveHoverProvider());
|
||||
providers.put(
|
||||
org.springframework.ide.vscode.boot.java.conditionals.Constants.CONDITIONAL_ON_ENABLED_RESOURCE_CHAIN,
|
||||
providers.put(Annotations.CONDITIONAL_ON_ENABLED_RESOURCE_CHAIN,
|
||||
new ConditionalsLiveHoverProvider());
|
||||
providers.put(org.springframework.ide.vscode.boot.java.conditionals.Constants.CONDITIONAL_ON_ENABLED_ENDPOINT,
|
||||
providers.put(Annotations.CONDITIONAL_ON_ENABLED_ENDPOINT,
|
||||
new ConditionalsLiveHoverProvider());
|
||||
providers.put(
|
||||
org.springframework.ide.vscode.boot.java.conditionals.Constants.CONDITIONAL_ON_ENABLED_HEALTH_INDICATOR,
|
||||
providers.put(Annotations.CONDITIONAL_ON_ENABLED_HEALTH_INDICATOR,
|
||||
new ConditionalsLiveHoverProvider());
|
||||
providers.put(org.springframework.ide.vscode.boot.java.conditionals.Constants.CONDITIONAL_ON_EXPRESSION,
|
||||
providers.put(Annotations.CONDITIONAL_ON_EXPRESSION,
|
||||
new ConditionalsLiveHoverProvider());
|
||||
providers.put(org.springframework.ide.vscode.boot.java.conditionals.Constants.CONDITIONAL_ON_JAVA,
|
||||
providers.put(Annotations.CONDITIONAL_ON_JAVA,
|
||||
new ConditionalsLiveHoverProvider());
|
||||
providers.put(org.springframework.ide.vscode.boot.java.conditionals.Constants.CONDITIONAL_ON_JNDI,
|
||||
providers.put(Annotations.CONDITIONAL_ON_JNDI,
|
||||
new ConditionalsLiveHoverProvider());
|
||||
providers.put(org.springframework.ide.vscode.boot.java.conditionals.Constants.CONDITIONAL_ON_SINGLE_CANDIDATE,
|
||||
providers.put(Annotations.CONDITIONAL_ON_SINGLE_CANDIDATE,
|
||||
new ConditionalsLiveHoverProvider());
|
||||
|
||||
return new BootJavaHoverProvider(this, javaProjectFinder, providers, runningAppProvider);
|
||||
@@ -309,17 +305,17 @@ public class BootJavaLanguageServer extends SimpleLanguageServer {
|
||||
|
||||
protected SpringIndexer createAnnotationIndexer(SimpleLanguageServer server, JavaProjectFinder projectFinder) {
|
||||
HashMap<String, SymbolProvider> providers = new HashMap<>();
|
||||
providers.put(org.springframework.ide.vscode.boot.java.requestmapping.Constants.SPRING_REQUEST_MAPPING,
|
||||
providers.put(Annotations.SPRING_REQUEST_MAPPING,
|
||||
new RequestMappingSymbolProvider());
|
||||
providers.put(org.springframework.ide.vscode.boot.java.requestmapping.Constants.SPRING_GET_MAPPING,
|
||||
providers.put(Annotations.SPRING_GET_MAPPING,
|
||||
new RequestMappingSymbolProvider());
|
||||
providers.put(org.springframework.ide.vscode.boot.java.requestmapping.Constants.SPRING_POST_MAPPING,
|
||||
providers.put(Annotations.SPRING_POST_MAPPING,
|
||||
new RequestMappingSymbolProvider());
|
||||
providers.put(org.springframework.ide.vscode.boot.java.requestmapping.Constants.SPRING_PUT_MAPPING,
|
||||
providers.put(Annotations.SPRING_PUT_MAPPING,
|
||||
new RequestMappingSymbolProvider());
|
||||
providers.put(org.springframework.ide.vscode.boot.java.requestmapping.Constants.SPRING_DELETE_MAPPING,
|
||||
providers.put(Annotations.SPRING_DELETE_MAPPING,
|
||||
new RequestMappingSymbolProvider());
|
||||
providers.put(org.springframework.ide.vscode.boot.java.requestmapping.Constants.SPRING_PATCH_MAPPING,
|
||||
providers.put(Annotations.SPRING_PATCH_MAPPING,
|
||||
new RequestMappingSymbolProvider());
|
||||
|
||||
providers.put(Annotations.BEAN, new BeansSymbolProvider());
|
||||
|
||||
@@ -12,7 +12,6 @@ package org.springframework.ide.vscode.boot.java.conditionals;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
@@ -27,13 +26,11 @@ import org.eclipse.lsp4j.Hover;
|
||||
import org.eclipse.lsp4j.MarkedString;
|
||||
import org.eclipse.lsp4j.Range;
|
||||
import org.eclipse.lsp4j.jsonrpc.messages.Either;
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONObject;
|
||||
import org.springframework.ide.vscode.boot.java.handlers.HoverProvider;
|
||||
import org.springframework.ide.vscode.boot.java.utils.HoverContentUtils;
|
||||
import org.springframework.ide.vscode.commons.boot.app.cli.LiveConditional;
|
||||
import org.springframework.ide.vscode.commons.boot.app.cli.SpringBootApp;
|
||||
import org.springframework.ide.vscode.commons.java.IJavaProject;
|
||||
import org.springframework.ide.vscode.commons.util.BadLocationException;
|
||||
import org.springframework.ide.vscode.commons.util.Log;
|
||||
import org.springframework.ide.vscode.commons.util.text.TextDocument;
|
||||
|
||||
@@ -55,28 +52,45 @@ public class ConditionalsLiveHoverProvider implements HoverProvider {
|
||||
@Override
|
||||
public Collection<Range> getLiveHoverHints(Annotation annotation, TextDocument doc, SpringBootApp[] runningApps) {
|
||||
try {
|
||||
if (runningApps.length > 0) {
|
||||
ConditionalParserFromRunningApp parser = new ConditionalParserFromRunningApp();
|
||||
Optional<List<RunningAppConditional>> val = parser.parse(annotation, runningApps);
|
||||
if (val.isPresent()) {
|
||||
Range hoverRange = doc.toRange(annotation.getStartPosition(), annotation.getLength());
|
||||
return ImmutableList.of(hoverRange);
|
||||
}
|
||||
Optional<List<LiveConditional>> val = getMatchedLiveConditionals(annotation, runningApps);
|
||||
if (val.isPresent()) {
|
||||
Range hoverRange = doc.toRange(annotation.getStartPosition(), annotation.getLength());
|
||||
return ImmutableList.of(hoverRange);
|
||||
}
|
||||
} catch (BadLocationException e) {
|
||||
} catch (Exception e) {
|
||||
Log.log(e);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private Optional<List<LiveConditional>> getMatchedLiveConditionals(Annotation annotation,
|
||||
SpringBootApp[] runningApps) throws Exception {
|
||||
if (runningApps != null) {
|
||||
List<LiveConditional> all = new ArrayList<>();
|
||||
|
||||
for (SpringBootApp springBootApp : runningApps) {
|
||||
springBootApp.getLiveConditionals().ifPresent((conditionals) -> {
|
||||
conditionals.stream().forEach((conditional) -> {
|
||||
if (matchesAnnotation(annotation, conditional)) {
|
||||
all.add(conditional);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
if (!all.isEmpty()) {
|
||||
return Optional.of(all);
|
||||
}
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
private CompletableFuture<Hover> provideHover(Annotation annotation, TextDocument doc,
|
||||
SpringBootApp[] runningApps) {
|
||||
|
||||
try {
|
||||
List<Either<String, MarkedString>> hoverContent = new ArrayList<>();
|
||||
ConditionalParserFromRunningApp parser = new ConditionalParserFromRunningApp();
|
||||
Optional<List<RunningAppConditional>> val = parser.parse(annotation, runningApps);
|
||||
Optional<List<LiveConditional>> val = getMatchedLiveConditionals(annotation, runningApps);
|
||||
|
||||
if (val.isPresent()) {
|
||||
addHoverContent(val.get(), hoverContent);
|
||||
@@ -96,151 +110,43 @@ public class ConditionalsLiveHoverProvider implements HoverProvider {
|
||||
return null;
|
||||
}
|
||||
|
||||
private void addHoverContent(List<RunningAppConditional> conditions,
|
||||
List<Either<String, MarkedString>> hoverContent) throws Exception {
|
||||
for (int i = 0; i < conditions.size(); i++) {
|
||||
RunningAppConditional condition = conditions.get(i);
|
||||
hoverContent.add(Either.forLeft(condition.message));
|
||||
hoverContent.add(Either
|
||||
.forLeft(HoverContentUtils.getProcessInformation(condition.app)));
|
||||
private void addHoverContent(List<LiveConditional> conditionals, List<Either<String, MarkedString>> hoverContent)
|
||||
throws Exception {
|
||||
for (int i = 0; i < conditionals.size(); i++) {
|
||||
LiveConditional conditional = conditionals.get(i);
|
||||
hoverContent.add(Either.forLeft(conditional.getMessage()));
|
||||
hoverContent.add(Either.forLeft(HoverContentUtils.getProcessInformation(conditional.getProcessId(), conditional.getProcessName())));
|
||||
|
||||
if (i < conditions.size() - 1) {
|
||||
if (i < conditionals.size() - 1) {
|
||||
hoverContent.add(Either.forLeft("---"));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parsers @ConditionalOn annotations from a spring boot running app's
|
||||
* autoconfig report. An example of a conditional that is parsed from a running
|
||||
* app's autoconfig report would be:
|
||||
*
|
||||
* {"TraceRepositoryAutoConfiguration#traceRepository":[{"condition":"OnBeanCondition","message":"@ConditionalOnMissingBean
|
||||
* (types: org.springframework.boot.actuate.trace.TraceRepository;
|
||||
* SearchStrategy: all) did not find any beans"}]
|
||||
*
|
||||
* @param annotation
|
||||
* @param jsonKey
|
||||
* @return true if the annotation matches the information in the json key from
|
||||
* the running app.
|
||||
*/
|
||||
public static class ConditionalParserFromRunningApp {
|
||||
protected boolean matchesAnnotation(Annotation annotation, LiveConditional liveConditional) {
|
||||
|
||||
public Optional<List<RunningAppConditional>> parse(Annotation annotation, SpringBootApp[] runningApps) {
|
||||
ASTNode parent = annotation.getParent();
|
||||
String rawJsonKey = liveConditional.getPositiveMatchKey();
|
||||
|
||||
try {
|
||||
List<RunningAppConditional> allConditionals = new ArrayList<>();
|
||||
for (SpringBootApp app : runningApps) {
|
||||
String autoConfigRecord = app.getAutoConfigReport();
|
||||
if (autoConfigRecord != null) {
|
||||
JSONObject autoConfigJson = new JSONObject(autoConfigRecord);
|
||||
List<RunningAppConditional> conditionalsFromPositiveMatches = getConditionals(app, annotation,
|
||||
autoConfigJson);
|
||||
if (!conditionalsFromPositiveMatches.isEmpty()) {
|
||||
allConditionals.addAll(conditionalsFromPositiveMatches);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!allConditionals.isEmpty()) {
|
||||
return Optional.of(allConditionals);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.log(e);
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param app
|
||||
* @param annotation
|
||||
* @param autoConfigJson
|
||||
* @return non-null list of conditionals parsed from an autoconfig report. List
|
||||
* may be empty.
|
||||
*/
|
||||
private List<RunningAppConditional> getConditionals(SpringBootApp app, Annotation annotation,
|
||||
JSONObject autoConfigJson) {
|
||||
List<RunningAppConditional> conditions = new ArrayList<>();
|
||||
|
||||
getPositiveMatches(autoConfigJson).ifPresent((positiveMatches) -> {
|
||||
Iterator<String> pMKeys = positiveMatches.keys();
|
||||
while (pMKeys.hasNext()) {
|
||||
String positiveMatchKey = pMKeys.next();
|
||||
if (matchesAnnotation(annotation, positiveMatchKey)) {
|
||||
JSONArray matchList = (JSONArray) positiveMatches.get(positiveMatchKey);
|
||||
matchList.forEach((match) -> {
|
||||
if (match instanceof JSONObject) {
|
||||
getMatchedCondition(app, (JSONObject) match, annotation)
|
||||
.ifPresent((condition) -> conditions.add(condition));
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return conditions;
|
||||
}
|
||||
|
||||
protected Optional<JSONObject> getPositiveMatches(JSONObject autoConfigJson) {
|
||||
|
||||
Iterator<String> keys = autoConfigJson.keys();
|
||||
|
||||
while (keys.hasNext()) {
|
||||
String key = keys.next();
|
||||
if ("positiveMatches".equals(key)) {
|
||||
Object obj = autoConfigJson.get(key);
|
||||
if (obj instanceof JSONObject) {
|
||||
return Optional.of((JSONObject) obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param annotation
|
||||
* @param jsonKey
|
||||
* @return true if the annotation matches the information in the json key from
|
||||
* the running app.
|
||||
*/
|
||||
protected boolean matchesAnnotation(Annotation annotation, String jsonKey) {
|
||||
|
||||
ASTNode parent = annotation.getParent();
|
||||
if (parent instanceof MethodDeclaration) {
|
||||
MethodDeclaration methodDec = (MethodDeclaration) parent;
|
||||
IMethodBinding binding = methodDec.resolveBinding();
|
||||
String annotationDeclaringClassName = binding.getDeclaringClass().getName();
|
||||
String annotationMethodName = binding.getName();
|
||||
return jsonKey.contains(annotationDeclaringClassName) && jsonKey.contains(annotationMethodName);
|
||||
} else if (parent instanceof TypeDeclaration) {
|
||||
TypeDeclaration typeDec = (TypeDeclaration) parent;
|
||||
String annotationDeclaringClassName = typeDec.resolveBinding().getName();
|
||||
return jsonKey.contains(annotationDeclaringClassName);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
protected Optional<RunningAppConditional> getMatchedCondition(SpringBootApp app, JSONObject conditionJson,
|
||||
Annotation annotation) {
|
||||
if (conditionJson != null) {
|
||||
String condition = (String) conditionJson.get("condition");
|
||||
String message = (String) conditionJson.get("message");
|
||||
String annotationName = annotation.resolveTypeBinding().getName();
|
||||
if (message.contains(annotationName)) {
|
||||
return Optional.of(new RunningAppConditional(app, condition, message));
|
||||
}
|
||||
}
|
||||
return Optional.empty();
|
||||
if (parent instanceof MethodDeclaration) {
|
||||
MethodDeclaration methodDec = (MethodDeclaration) parent;
|
||||
IMethodBinding binding = methodDec.resolveBinding();
|
||||
String annotationDeclaringClassName = binding.getDeclaringClass().getName();
|
||||
String annotationMethodName = binding.getName();
|
||||
return rawJsonKey.contains(annotationDeclaringClassName) && rawJsonKey.contains(annotationMethodName);
|
||||
} else if (parent instanceof TypeDeclaration) {
|
||||
TypeDeclaration typeDec = (TypeDeclaration) parent;
|
||||
String annotationDeclaringClassName = typeDec.resolveBinding().getName();
|
||||
return rawJsonKey.contains(annotationDeclaringClassName);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public static class RunningAppConditional {
|
||||
|
||||
public final String condition;
|
||||
public final String message;
|
||||
public final SpringBootApp app;
|
||||
|
||||
public RunningAppConditional(SpringBootApp app, String condition, String message) {
|
||||
this.condition = condition;
|
||||
this.message = message;
|
||||
this.app = app;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,33 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* 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.conditionals;
|
||||
|
||||
public class Constants {
|
||||
|
||||
public static final String CONDITIONAL = "org.springframework.context.annotation.Conditional";
|
||||
public static final String CONDITIONAL_ON_BEAN = "org.springframework.boot.autoconfigure.condition.ConditionalOnBean";
|
||||
public static final String CONDITIONAL_ON_MISSING_BEAN = "org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean";
|
||||
public static final String CONDITIONAL_ON_PROPERTY = "org.springframework.boot.autoconfigure.condition.ConditionalOnProperty";
|
||||
public static final String CONDITIONAL_ON_RESOURCE = "org.springframework.boot.autoconfigure.condition.ConditionalOnResource";
|
||||
public static final String CONDITIONAL_ON_CLASS = "org.springframework.boot.autoconfigure.condition.ConditionalOnClass";
|
||||
public static final String CONDITIONAL_ON_MISSING_CLASS = "org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass";
|
||||
public static final String CONDITIONAL_ON_CLOUD_PLATFORM = "org.springframework.boot.autoconfigure.condition.ConditionalOnCloudPlatform";
|
||||
public static final String CONDITIONAL_ON_WEB_APPLICATION = "org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication";
|
||||
public static final String CONDITIONAL_ON_NOT_WEB_APPLICATION = "org.springframework.boot.autoconfigure.condition.ConditionalOnNotWebApplication";
|
||||
public static final String CONDITIONAL_ON_ENABLED_INFO_CONTRIBUTOR = "org.springframework.boot.actuate.autoconfigure.ConditionalOnEnabledInfoContributor";
|
||||
public static final String CONDITIONAL_ON_ENABLED_RESOURCE_CHAIN = "org.springframework.boot.autoconfigure.web.ConditionalOnEnabledResourceChain";
|
||||
public static final String CONDITIONAL_ON_ENABLED_ENDPOINT = "org.springframework.boot.actuate.condition.ConditionalOnEnabledEndpoint";
|
||||
public static final String CONDITIONAL_ON_ENABLED_HEALTH_INDICATOR = "org.springframework.boot.actuate.autoconfigure.ConditionalOnEnabledHealthIndicator";
|
||||
public static final String CONDITIONAL_ON_EXPRESSION = "org.springframework.boot.autoconfigure.condition.ConditionalOnExpression";
|
||||
public static final String CONDITIONAL_ON_JAVA = "org.springframework.boot.autoconfigure.condition.ConditionalOnJava";
|
||||
public static final String CONDITIONAL_ON_JNDI = "org.springframework.boot.autoconfigure.condition.ConditionalOnJndi";
|
||||
public static final String CONDITIONAL_ON_SINGLE_CANDIDATE = "org.springframework.boot.autoconfigure.condition.ConditionalOnSingleCandidate";
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
/*******************************************************************************
|
||||
* 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.requestmapping;
|
||||
|
||||
/**
|
||||
* @author Martin Lippert
|
||||
*/
|
||||
public class Constants {
|
||||
|
||||
public static final String SPRING_REQUEST_MAPPING = "org.springframework.web.bind.annotation.RequestMapping";
|
||||
public static final String SPRING_GET_MAPPING = "org.springframework.web.bind.annotation.GetMapping";
|
||||
public static final String SPRING_POST_MAPPING = "org.springframework.web.bind.annotation.PostMapping";
|
||||
public static final String SPRING_PUT_MAPPING = "org.springframework.web.bind.annotation.PutMapping";
|
||||
public static final String SPRING_DELETE_MAPPING = "org.springframework.web.bind.annotation.DeleteMapping";
|
||||
public static final String SPRING_PATCH_MAPPING = "org.springframework.web.bind.annotation.PatchMapping";
|
||||
|
||||
}
|
||||
@@ -30,6 +30,7 @@ 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.Annotations;
|
||||
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;
|
||||
@@ -142,7 +143,7 @@ public class RequestMappingSymbolProvider implements SymbolProvider {
|
||||
Annotation annotation = (Annotation) modifier;
|
||||
ITypeBinding resolvedType = annotation.resolveTypeBinding();
|
||||
String annotationType = resolvedType.getQualifiedName();
|
||||
if (annotationType != null && Constants.SPRING_REQUEST_MAPPING.equals(annotationType)) {
|
||||
if (annotationType != null && Annotations.SPRING_REQUEST_MAPPING.equals(annotationType)) {
|
||||
return annotation;
|
||||
}
|
||||
}
|
||||
@@ -155,15 +156,15 @@ public class RequestMappingSymbolProvider implements SymbolProvider {
|
||||
ITypeBinding type = annotation.resolveTypeBinding();
|
||||
if (type != null) {
|
||||
switch (type.getQualifiedName()) {
|
||||
case Constants.SPRING_GET_MAPPING:
|
||||
case Annotations.SPRING_GET_MAPPING:
|
||||
return new String[] { "GET" };
|
||||
case Constants.SPRING_POST_MAPPING:
|
||||
case Annotations.SPRING_POST_MAPPING:
|
||||
return new String[] { "POST" };
|
||||
case Constants.SPRING_DELETE_MAPPING:
|
||||
case Annotations.SPRING_DELETE_MAPPING:
|
||||
return new String[] { "DELETE" };
|
||||
case Constants.SPRING_PUT_MAPPING:
|
||||
case Annotations.SPRING_PUT_MAPPING:
|
||||
return new String[] { "PUT" };
|
||||
case Constants.SPRING_PATCH_MAPPING:
|
||||
case Annotations.SPRING_PATCH_MAPPING:
|
||||
return new String[] { "PATCH" };
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,11 @@ import org.springframework.ide.vscode.commons.boot.app.cli.SpringBootApp;
|
||||
public class HoverContentUtils {
|
||||
|
||||
public static String getProcessInformation(SpringBootApp app) {
|
||||
return "Process " + app.getProcessID() + ": " + app.getProcessName();
|
||||
return getProcessInformation(app.getProcessID(), app.getProcessName());
|
||||
}
|
||||
|
||||
public static String getProcessInformation(String processId, String processName) {
|
||||
return "Process " + processId + ": " + processName;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -67,7 +67,7 @@ public class ConditionalsLiveHoverTest {
|
||||
// Build a mock running boot app
|
||||
mockAppProvider.builder().isSpringBootApp(true).port("1111").processId("22022").host("cfapps.io")
|
||||
.processName("test-conditionals-live-hover")
|
||||
.getAutoConfigReport(
|
||||
.getLiveConditionals(
|
||||
"{\"positiveMatches\":{\"ConditionalOnBeanConfig#hi\":[{\"condition\":\"OnBeanCondition\",\"message\":\"@ConditionalOnBean (types: example.Hello; SearchStrategy: all) found bean 'missing'\"}]}}")
|
||||
.build();
|
||||
|
||||
@@ -91,7 +91,7 @@ public class ConditionalsLiveHoverTest {
|
||||
// Build a mock running boot app
|
||||
mockAppProvider.builder().isSpringBootApp(true).port("1111").processId("22022").host("cfapps.io")
|
||||
.processName("test-conditionals-live-hover")
|
||||
.getAutoConfigReport(
|
||||
.getLiveConditionals(
|
||||
"{\"positiveMatches\":{\"ConditionalOnMissingBeanConfig#missing\":[{\"condition\":\"OnBeanCondition\",\"message\":\"@ConditionalOnMissingBean (types: example.Hello; SearchStrategy: all) did not find any beans\"}]}}")
|
||||
.build();
|
||||
|
||||
@@ -114,7 +114,7 @@ public class ConditionalsLiveHoverTest {
|
||||
// Build a mock running boot app
|
||||
mockAppProvider.builder().isSpringBootApp(true).port("1111").processId("22022").host("cfapps.io")
|
||||
.processName("test-conditionals-live-hover")
|
||||
.getAutoConfigReport(
|
||||
.getLiveConditionals(
|
||||
"{\"positiveMatches\":{\"HelloConfig#missing\":[{\"condition\":\"OnBeanCondition\",\"message\":\"@ConditionalOnMissingBean (types: example.Hello; SearchStrategy: all) did not find any beans\"}],\"HelloConfig2#hi\":[{\"condition\":\"OnBeanCondition\",\"message\":\"@ConditionalOnBean (types: example.Hello; SearchStrategy: all) found bean 'missing'\"}],\"MultipleConditionals#hi\":[{\"condition\":\"OnClassCondition\",\"message\":\"@ConditionalOnClass found required class; @ConditionalOnMissingClass did not find unwanted class\"},{\"condition\":\"OnWebApplicationCondition\",\"message\":\"@ConditionalOnWebApplication (required) found StandardServletEnvironment\"},{\"condition\":\"OnJavaCondition\",\"message\":\"@ConditionalOnJava (1.8 or newer) found 1.8\"},{\"condition\":\"OnExpressionCondition\",\"message\":\"@ConditionalOnExpression (#{true}) resulted in true\"},{\"condition\":\"OnBeanCondition\",\"message\":\"@ConditionalOnBean (types: example.Hello; SearchStrategy: all) found beans 'hi', 'missing'\"}]}}")
|
||||
.build();
|
||||
|
||||
@@ -156,19 +156,19 @@ public class ConditionalsLiveHoverTest {
|
||||
// Build a mock running boot app
|
||||
mockAppProvider.builder().isSpringBootApp(true).port("1000").processId("70000").host("cfapps.io")
|
||||
.processName("test-conditionals-live-hover")
|
||||
.getAutoConfigReport(
|
||||
.getLiveConditionals(
|
||||
"{\"positiveMatches\":{\"ConditionalOnMissingBeanConfig#missing\":[{\"condition\":\"OnBeanCondition\",\"message\":\"@ConditionalOnMissingBean (types: example.Hello; SearchStrategy: all) did not find any beans\"}]}}")
|
||||
.build();
|
||||
|
||||
mockAppProvider.builder().isSpringBootApp(true).port("1001").processId("80000").host("cfapps.io")
|
||||
.processName("test-conditionals-live-hover")
|
||||
.getAutoConfigReport(
|
||||
.getLiveConditionals(
|
||||
"{\"positiveMatches\":{\"ConditionalOnMissingBeanConfig#missing\":[{\"condition\":\"OnBeanCondition\",\"message\":\"@ConditionalOnMissingBean (types: example.Hello; SearchStrategy: all) did not find any beans\"}]}}")
|
||||
.build();
|
||||
|
||||
mockAppProvider.builder().isSpringBootApp(true).port("1002").processId("90000").host("cfapps.io")
|
||||
.processName("test-conditionals-live-hover")
|
||||
.getAutoConfigReport(
|
||||
.getLiveConditionals(
|
||||
"{\"positiveMatches\":{\"ConditionalOnMissingBeanConfig#missing\":[{\"condition\":\"OnBeanCondition\",\"message\":\"@ConditionalOnMissingBean (types: example.Hello; SearchStrategy: all) did not find any beans\"}]}}")
|
||||
.build();
|
||||
|
||||
|
||||
@@ -27,9 +27,9 @@ import org.apache.commons.io.FileUtils;
|
||||
import org.eclipse.lsp4j.SymbolInformation;
|
||||
import org.junit.Before;
|
||||
import org.junit.Test;
|
||||
import org.springframework.ide.vscode.boot.java.Annotations;
|
||||
import org.springframework.ide.vscode.boot.java.BootJavaLanguageServer;
|
||||
import org.springframework.ide.vscode.boot.java.handlers.SymbolProvider;
|
||||
import org.springframework.ide.vscode.boot.java.requestmapping.Constants;
|
||||
import org.springframework.ide.vscode.boot.java.requestmapping.RequestMappingSymbolProvider;
|
||||
import org.springframework.ide.vscode.boot.java.utils.SpringIndexer;
|
||||
import org.springframework.ide.vscode.commons.maven.MavenCore;
|
||||
@@ -53,7 +53,7 @@ public class SpringIndexerTest {
|
||||
@Before
|
||||
public void setup() throws Exception {
|
||||
symbolProviders = new HashMap<>();
|
||||
symbolProviders.put(Constants.SPRING_REQUEST_MAPPING, new RequestMappingSymbolProvider());
|
||||
symbolProviders.put(Annotations.SPRING_REQUEST_MAPPING, new RequestMappingSymbolProvider());
|
||||
harness = BootLanguageServerHarness.builder().build();
|
||||
}
|
||||
|
||||
|
||||
@@ -19,8 +19,8 @@ import java.util.Collection;
|
||||
import org.mockito.Mockito;
|
||||
import org.springframework.ide.vscode.boot.java.handlers.RunningAppProvider;
|
||||
import org.springframework.ide.vscode.commons.boot.app.cli.SpringBootApp;
|
||||
import org.springframework.ide.vscode.commons.boot.app.cli.requestmappings.RequestMapping;
|
||||
import org.springframework.ide.vscode.commons.boot.app.cli.livebean.LiveBeansModel;
|
||||
import org.springframework.ide.vscode.commons.boot.app.cli.requestmappings.RequestMapping;
|
||||
import org.springframework.ide.vscode.commons.util.ExceptionUtil;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
@@ -57,6 +57,8 @@ public class MockRunningAppProvider {
|
||||
public static class MockAppBuilder {
|
||||
public final SpringBootApp app = mock(SpringBootApp.class);
|
||||
private MockRunningAppProvider runningAppProvider;
|
||||
private String processId;
|
||||
private String processName;
|
||||
|
||||
public MockAppBuilder(MockRunningAppProvider runningAppProvider) {
|
||||
this.runningAppProvider = runningAppProvider;
|
||||
@@ -77,11 +79,13 @@ public class MockRunningAppProvider {
|
||||
}
|
||||
|
||||
public MockAppBuilder processId(String processId) {
|
||||
this.processId = processId;
|
||||
when(app.getProcessID()).thenReturn(processId);
|
||||
return this;
|
||||
}
|
||||
|
||||
public MockAppBuilder processName(String name) {
|
||||
this.processName = name;
|
||||
when(app.getProcessName()).thenReturn(name);
|
||||
return this;
|
||||
}
|
||||
@@ -112,6 +116,11 @@ public class MockRunningAppProvider {
|
||||
return this;
|
||||
}
|
||||
|
||||
public MockAppBuilder getLiveConditionals(String autoConfigReport) throws Exception{
|
||||
when(app.getLiveConditionals()).thenReturn(SpringBootApp.getLiveConditionals(autoConfigReport, processId, processName));
|
||||
return this;
|
||||
}
|
||||
|
||||
public MockAppBuilder profiles(String... names) {
|
||||
when(app.getActiveProfiles()).thenReturn(ImmutableList.copyOf(names));
|
||||
return this;
|
||||
|
||||
@@ -0,0 +1,89 @@
|
||||
/*******************************************************************************
|
||||
* 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.commons.boot.app.cli;
|
||||
|
||||
public class LiveConditional {
|
||||
|
||||
private String condition;
|
||||
private String message;
|
||||
private String processId;
|
||||
private String processName;
|
||||
private String positiveMatchKey;
|
||||
|
||||
public LiveConditional() {
|
||||
|
||||
}
|
||||
|
||||
public String getCondition() {
|
||||
return condition;
|
||||
}
|
||||
|
||||
public String getMessage() {
|
||||
return message;
|
||||
}
|
||||
|
||||
public String getProcessId() {
|
||||
return processId;
|
||||
}
|
||||
|
||||
public String getProcessName() {
|
||||
return processName;
|
||||
}
|
||||
|
||||
public String getPositiveMatchKey() {
|
||||
return positiveMatchKey;
|
||||
}
|
||||
|
||||
public static class LiveConditionalBuilder {
|
||||
|
||||
private LiveConditional conditional = new LiveConditional();
|
||||
|
||||
public LiveConditionalBuilder condition(String condition) {
|
||||
conditional.condition = condition;
|
||||
return this;
|
||||
}
|
||||
|
||||
public LiveConditionalBuilder message(String message) {
|
||||
conditional.message = message;
|
||||
return this;
|
||||
}
|
||||
|
||||
public LiveConditionalBuilder processId(String processId) {
|
||||
conditional.processId = processId;
|
||||
return this;
|
||||
}
|
||||
|
||||
public LiveConditionalBuilder processName(String processName) {
|
||||
conditional.processName = processName;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* This is a JSON key in "positiveMatches" element in the autoconfig report that contains information regarding
|
||||
* the method that the conditional is applied to.
|
||||
* @param positiveMatchKey
|
||||
* @return
|
||||
*/
|
||||
public LiveConditionalBuilder positiveMatchKey(String positiveMatchKey) {
|
||||
conditional.positiveMatchKey = positiveMatchKey;
|
||||
return this;
|
||||
}
|
||||
|
||||
public LiveConditional build() {
|
||||
return conditional;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public static LiveConditionalBuilder builder() {
|
||||
return new LiveConditionalBuilder();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
/*******************************************************************************
|
||||
* 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.commons.boot.app.cli;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONObject;
|
||||
import org.springframework.ide.vscode.commons.util.Log;
|
||||
import org.springframework.ide.vscode.commons.util.StringUtil;
|
||||
|
||||
/**
|
||||
* Parsers @ConditionalOn annotations from a spring boot running app's
|
||||
* autoconfig report. An example of a conditional that is parsed from a running
|
||||
* app's autoconfig report would be:
|
||||
*
|
||||
* {"TraceRepositoryAutoConfiguration#traceRepository":[{"condition":"OnBeanCondition","message":"@ConditionalOnMissingBean
|
||||
* (types: org.springframework.boot.actuate.trace.TraceRepository;
|
||||
* SearchStrategy: all) did not find any beans"}]
|
||||
*
|
||||
*/
|
||||
public class LiveConditionalParser {
|
||||
|
||||
private final String autoConfigRecord;
|
||||
private final String appProcessName;
|
||||
private final String appProcessId;
|
||||
|
||||
public LiveConditionalParser(String autoConfigRecord, String appProcessId, String appProcessName) {
|
||||
this.autoConfigRecord = autoConfigRecord;
|
||||
this.appProcessId = appProcessId;
|
||||
this.appProcessName = appProcessName;
|
||||
}
|
||||
|
||||
public Optional<List<LiveConditional>> parse() {
|
||||
|
||||
try {
|
||||
List<LiveConditional> allConditionals = new ArrayList<>();
|
||||
|
||||
if (StringUtil.hasText(autoConfigRecord)) {
|
||||
getConditionalsFromPositiveMatches(autoConfigRecord).stream()
|
||||
.forEach(conditional -> allConditionals.add(conditional));
|
||||
}
|
||||
if (!allConditionals.isEmpty()) {
|
||||
return Optional.of(allConditionals);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.log(e);
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches the "positiveMatches" element in the autoconfig report that contains conditional information.
|
||||
* @param positiveMatchKey
|
||||
* @return
|
||||
*/
|
||||
private Optional<JSONObject> getPositiveMatchesJson(String autoConfigReport) {
|
||||
JSONObject autoConfigJson = new JSONObject(autoConfigReport);
|
||||
|
||||
Iterator<String> keys = autoConfigJson.keys();
|
||||
|
||||
while (keys.hasNext()) {
|
||||
String key = keys.next();
|
||||
if ("positiveMatches".equals(key)) {
|
||||
Object obj = autoConfigJson.get(key);
|
||||
if (obj instanceof JSONObject) {
|
||||
return Optional.of((JSONObject) obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetches all the conditionals listed in the the "positiveMatches" element in the autoconfig report.
|
||||
*
|
||||
*/
|
||||
private List<LiveConditional> getConditionalsFromPositiveMatches(String autoconfigReport) {
|
||||
List<LiveConditional> conditions = new ArrayList<>();
|
||||
|
||||
getPositiveMatchesJson(autoconfigReport).ifPresent((positiveMatches) -> {
|
||||
Iterator<String> pMKeys = positiveMatches.keys();
|
||||
while (pMKeys.hasNext()) {
|
||||
// The positive match key contains the bean method information where conditional
|
||||
// was applied to
|
||||
String positiveMatchKey = pMKeys.next();
|
||||
JSONArray matchList = (JSONArray) positiveMatches.get(positiveMatchKey);
|
||||
matchList.forEach((match) -> {
|
||||
if (match instanceof JSONObject) {
|
||||
resolveConditional(positiveMatchKey, (JSONObject) match)
|
||||
.ifPresent((condition) -> conditions.add(condition));
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return conditions;
|
||||
}
|
||||
|
||||
private Optional<LiveConditional> resolveConditional(String positiveMatchKey, JSONObject conditionalJson) {
|
||||
if (conditionalJson != null) {
|
||||
String condition = (String) conditionalJson.get("condition");
|
||||
String message = (String) conditionalJson.get("message");
|
||||
// We care about the message itself as it contains the actual annotation as well
|
||||
// as the reason it matched
|
||||
if (StringUtil.hasText(message)) {
|
||||
return Optional.of(LiveConditional.builder().processId(appProcessId).processName(appProcessName)
|
||||
.condition(condition).message(message).positiveMatchKey(positiveMatchKey).build());
|
||||
}
|
||||
}
|
||||
return Optional.empty();
|
||||
}
|
||||
|
||||
public static Optional<List<LiveConditional>> parse(String autoConfigRecord, String appProcessId,
|
||||
String appProcessName) {
|
||||
return new LiveConditionalParser(autoConfigRecord, appProcessId, appProcessName).parse();
|
||||
}
|
||||
}
|
||||
@@ -19,6 +19,7 @@ import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.Map.Entry;
|
||||
import java.util.Optional;
|
||||
import java.util.Properties;
|
||||
import java.util.Set;
|
||||
import java.util.StringTokenizer;
|
||||
@@ -235,6 +236,24 @@ public class SpringBootApp {
|
||||
return null;
|
||||
}
|
||||
|
||||
public Optional<List<LiveConditional>> getLiveConditionals() throws Exception {
|
||||
return getLiveConditionals(getAutoConfigReport(), getProcessID(), getProcessName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Publicly visible so that it can be tested via a mock app
|
||||
*
|
||||
* @param autoConfigReport
|
||||
* @param processId
|
||||
* @param processName
|
||||
* @return
|
||||
* @throws Exception
|
||||
*/
|
||||
public static Optional<List<LiveConditional>> getLiveConditionals(String autoConfigReport, String processId,
|
||||
String processName) {
|
||||
return new LiveConditionalParser(autoConfigReport, processId, processName).parse();
|
||||
}
|
||||
|
||||
public String getAutoConfigReport() throws Exception {
|
||||
Object result = getActuatorDataFromAttribute("org.springframework.boot:type=Endpoint,name=autoConfigurationReportEndpoint", "Data");
|
||||
if (result != null) {
|
||||
|
||||
Reference in New Issue
Block a user