diff --git a/eclipse-distribution/org.springframework.boot.ide.repository.e47/category.xml b/eclipse-distribution/org.springframework.boot.ide.repository.e47/category.xml
index d0bafb3c7..f69433447 100644
--- a/eclipse-distribution/org.springframework.boot.ide.repository.e47/category.xml
+++ b/eclipse-distribution/org.springframework.boot.ide.repository.e47/category.xml
@@ -79,6 +79,26 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/eclipse-distribution/pom.xml b/eclipse-distribution/pom.xml
index 6530e491b..bba04c789 100644
--- a/eclipse-distribution/pom.xml
+++ b/eclipse-distribution/pom.xml
@@ -113,16 +113,16 @@
p2
http://download.eclipse.org/releases/oxygen/
-
+
+
latest-m2e
p2
diff --git a/eclipse-language-servers/org.springframework.tooling.boot.java.ls.feature/feature.xml b/eclipse-language-servers/org.springframework.tooling.boot.java.ls.feature/feature.xml
index f928a6a9b..e344c175a 100644
--- a/eclipse-language-servers/org.springframework.tooling.boot.java.ls.feature/feature.xml
+++ b/eclipse-language-servers/org.springframework.tooling.boot.java.ls.feature/feature.xml
@@ -8,6 +8,7 @@
+
-
-
-
diff --git a/eclipse-language-servers/org.springframework.tooling.ls.eclipse.gotosymbol/META-INF/MANIFEST.MF b/eclipse-language-servers/org.springframework.tooling.ls.eclipse.gotosymbol/META-INF/MANIFEST.MF
index 21a586abd..04f7dc0dd 100644
--- a/eclipse-language-servers/org.springframework.tooling.ls.eclipse.gotosymbol/META-INF/MANIFEST.MF
+++ b/eclipse-language-servers/org.springframework.tooling.ls.eclipse.gotosymbol/META-INF/MANIFEST.MF
@@ -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
diff --git a/eclipse-language-servers/org.springframework.tooling.ls.eclipse.gotosymbol/src/org/springframework/tooling/ls/eclipse/gotosymbol/dialogs/GotoSymbolDialog.java b/eclipse-language-servers/org.springframework.tooling.ls.eclipse.gotosymbol/src/org/springframework/tooling/ls/eclipse/gotosymbol/dialogs/GotoSymbolDialog.java
index 0ed154737..a6f0aba60 100644
--- a/eclipse-language-servers/org.springframework.tooling.ls.eclipse.gotosymbol/src/org/springframework/tooling/ls/eclipse/gotosymbol/dialogs/GotoSymbolDialog.java
+++ b/eclipse-language-servers/org.springframework.tooling.ls.eclipse.gotosymbol/src/org/springframework/tooling/ls/eclipse/gotosymbol/dialogs/GotoSymbolDialog.java
@@ -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 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();
diff --git a/eclipse-language-servers/org.springframework.tooling.ls.integration.repository/category.xml b/eclipse-language-servers/org.springframework.tooling.ls.integration.repository/category.xml
index d904c61d5..efd9b37a9 100644
--- a/eclipse-language-servers/org.springframework.tooling.ls.integration.repository/category.xml
+++ b/eclipse-language-servers/org.springframework.tooling.ls.integration.repository/category.xml
@@ -32,6 +32,26 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/headless-services/boot-java-language-server/src/main/java/org/springframework/ide/vscode/boot/java/Annotations.java b/headless-services/boot-java-language-server/src/main/java/org/springframework/ide/vscode/boot/java/Annotations.java
index 19885dbf5..145feba88 100644
--- a/headless-services/boot-java-language-server/src/main/java/org/springframework/ide/vscode/boot/java/Annotations.java
+++ b/headless-services/boot-java-language-server/src/main/java/org/springframework/ide/vscode/boot/java/Annotations.java
@@ -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";
+
}
diff --git a/headless-services/boot-java-language-server/src/main/java/org/springframework/ide/vscode/boot/java/BootJavaLanguageServer.java b/headless-services/boot-java-language-server/src/main/java/org/springframework/ide/vscode/boot/java/BootJavaLanguageServer.java
index 41be1c788..ea021fa6c 100644
--- a/headless-services/boot-java-language-server/src/main/java/org/springframework/ide/vscode/boot/java/BootJavaLanguageServer.java
+++ b/headless-services/boot-java-language-server/src/main/java/org/springframework/ide/vscode/boot/java/BootJavaLanguageServer.java
@@ -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 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());
diff --git a/headless-services/boot-java-language-server/src/main/java/org/springframework/ide/vscode/boot/java/conditionals/ConditionalsLiveHoverProvider.java b/headless-services/boot-java-language-server/src/main/java/org/springframework/ide/vscode/boot/java/conditionals/ConditionalsLiveHoverProvider.java
index 19adceff4..6edc357b9 100644
--- a/headless-services/boot-java-language-server/src/main/java/org/springframework/ide/vscode/boot/java/conditionals/ConditionalsLiveHoverProvider.java
+++ b/headless-services/boot-java-language-server/src/main/java/org/springframework/ide/vscode/boot/java/conditionals/ConditionalsLiveHoverProvider.java
@@ -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 getLiveHoverHints(Annotation annotation, TextDocument doc, SpringBootApp[] runningApps) {
try {
- if (runningApps.length > 0) {
- ConditionalParserFromRunningApp parser = new ConditionalParserFromRunningApp();
- Optional> val = parser.parse(annotation, runningApps);
- if (val.isPresent()) {
- Range hoverRange = doc.toRange(annotation.getStartPosition(), annotation.getLength());
- return ImmutableList.of(hoverRange);
- }
+ Optional> 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> getMatchedLiveConditionals(Annotation annotation,
+ SpringBootApp[] runningApps) throws Exception {
+ if (runningApps != null) {
+ List 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 provideHover(Annotation annotation, TextDocument doc,
SpringBootApp[] runningApps) {
try {
List> hoverContent = new ArrayList<>();
- ConditionalParserFromRunningApp parser = new ConditionalParserFromRunningApp();
- Optional> val = parser.parse(annotation, runningApps);
+ Optional> 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 conditions,
- List> 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 conditionals, List> 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> parse(Annotation annotation, SpringBootApp[] runningApps) {
+ ASTNode parent = annotation.getParent();
+ String rawJsonKey = liveConditional.getPositiveMatchKey();
- try {
- List allConditionals = new ArrayList<>();
- for (SpringBootApp app : runningApps) {
- String autoConfigRecord = app.getAutoConfigReport();
- if (autoConfigRecord != null) {
- JSONObject autoConfigJson = new JSONObject(autoConfigRecord);
- List 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 getConditionals(SpringBootApp app, Annotation annotation,
- JSONObject autoConfigJson) {
- List conditions = new ArrayList<>();
-
- getPositiveMatches(autoConfigJson).ifPresent((positiveMatches) -> {
- Iterator 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 getPositiveMatches(JSONObject autoConfigJson) {
-
- Iterator 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 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;
- }
- }
}
diff --git a/headless-services/boot-java-language-server/src/main/java/org/springframework/ide/vscode/boot/java/conditionals/Constants.java b/headless-services/boot-java-language-server/src/main/java/org/springframework/ide/vscode/boot/java/conditionals/Constants.java
deleted file mode 100644
index 37e1cd7a0..000000000
--- a/headless-services/boot-java-language-server/src/main/java/org/springframework/ide/vscode/boot/java/conditionals/Constants.java
+++ /dev/null
@@ -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";
-}
diff --git a/headless-services/boot-java-language-server/src/main/java/org/springframework/ide/vscode/boot/java/requestmapping/Constants.java b/headless-services/boot-java-language-server/src/main/java/org/springframework/ide/vscode/boot/java/requestmapping/Constants.java
deleted file mode 100644
index 8d655ce30..000000000
--- a/headless-services/boot-java-language-server/src/main/java/org/springframework/ide/vscode/boot/java/requestmapping/Constants.java
+++ /dev/null
@@ -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";
-
-}
diff --git a/headless-services/boot-java-language-server/src/main/java/org/springframework/ide/vscode/boot/java/requestmapping/RequestMappingSymbolProvider.java b/headless-services/boot-java-language-server/src/main/java/org/springframework/ide/vscode/boot/java/requestmapping/RequestMappingSymbolProvider.java
index 620449c76..400826044 100644
--- a/headless-services/boot-java-language-server/src/main/java/org/springframework/ide/vscode/boot/java/requestmapping/RequestMappingSymbolProvider.java
+++ b/headless-services/boot-java-language-server/src/main/java/org/springframework/ide/vscode/boot/java/requestmapping/RequestMappingSymbolProvider.java
@@ -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" };
}
}
diff --git a/headless-services/boot-java-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/HoverContentUtils.java b/headless-services/boot-java-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/HoverContentUtils.java
index 5b34dea3c..7998a8443 100644
--- a/headless-services/boot-java-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/HoverContentUtils.java
+++ b/headless-services/boot-java-language-server/src/main/java/org/springframework/ide/vscode/boot/java/utils/HoverContentUtils.java
@@ -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;
}
}
diff --git a/headless-services/boot-java-language-server/src/test/java/org/springframework/ide/vscode/boot/java/conditionals/test/ConditionalsLiveHoverTest.java b/headless-services/boot-java-language-server/src/test/java/org/springframework/ide/vscode/boot/java/conditionals/test/ConditionalsLiveHoverTest.java
index ce876ca07..354c5cc64 100644
--- a/headless-services/boot-java-language-server/src/test/java/org/springframework/ide/vscode/boot/java/conditionals/test/ConditionalsLiveHoverTest.java
+++ b/headless-services/boot-java-language-server/src/test/java/org/springframework/ide/vscode/boot/java/conditionals/test/ConditionalsLiveHoverTest.java
@@ -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();
diff --git a/headless-services/boot-java-language-server/src/test/java/org/springframework/ide/vscode/boot/java/utils/test/SpringIndexerTest.java b/headless-services/boot-java-language-server/src/test/java/org/springframework/ide/vscode/boot/java/utils/test/SpringIndexerTest.java
index d5136414e..07a5664c9 100644
--- a/headless-services/boot-java-language-server/src/test/java/org/springframework/ide/vscode/boot/java/utils/test/SpringIndexerTest.java
+++ b/headless-services/boot-java-language-server/src/test/java/org/springframework/ide/vscode/boot/java/utils/test/SpringIndexerTest.java
@@ -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();
}
diff --git a/headless-services/boot-java-language-server/src/test/java/org/springframework/ide/vscode/project/harness/MockRunningAppProvider.java b/headless-services/boot-java-language-server/src/test/java/org/springframework/ide/vscode/project/harness/MockRunningAppProvider.java
index b06af7246..409fd34cb 100644
--- a/headless-services/boot-java-language-server/src/test/java/org/springframework/ide/vscode/project/harness/MockRunningAppProvider.java
+++ b/headless-services/boot-java-language-server/src/test/java/org/springframework/ide/vscode/project/harness/MockRunningAppProvider.java
@@ -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;
diff --git a/headless-services/commons/commons-boot-app-cli/src/main/java/org/springframework/ide/vscode/commons/boot/app/cli/LiveConditional.java b/headless-services/commons/commons-boot-app-cli/src/main/java/org/springframework/ide/vscode/commons/boot/app/cli/LiveConditional.java
new file mode 100644
index 000000000..3f4432838
--- /dev/null
+++ b/headless-services/commons/commons-boot-app-cli/src/main/java/org/springframework/ide/vscode/commons/boot/app/cli/LiveConditional.java
@@ -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();
+ }
+}
\ No newline at end of file
diff --git a/headless-services/commons/commons-boot-app-cli/src/main/java/org/springframework/ide/vscode/commons/boot/app/cli/LiveConditionalParser.java b/headless-services/commons/commons-boot-app-cli/src/main/java/org/springframework/ide/vscode/commons/boot/app/cli/LiveConditionalParser.java
new file mode 100644
index 000000000..e871989fd
--- /dev/null
+++ b/headless-services/commons/commons-boot-app-cli/src/main/java/org/springframework/ide/vscode/commons/boot/app/cli/LiveConditionalParser.java
@@ -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> parse() {
+
+ try {
+ List 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 getPositiveMatchesJson(String autoConfigReport) {
+ JSONObject autoConfigJson = new JSONObject(autoConfigReport);
+
+ Iterator 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 getConditionalsFromPositiveMatches(String autoconfigReport) {
+ List conditions = new ArrayList<>();
+
+ getPositiveMatchesJson(autoconfigReport).ifPresent((positiveMatches) -> {
+ Iterator 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 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> parse(String autoConfigRecord, String appProcessId,
+ String appProcessName) {
+ return new LiveConditionalParser(autoConfigRecord, appProcessId, appProcessName).parse();
+ }
+}
diff --git a/headless-services/commons/commons-boot-app-cli/src/main/java/org/springframework/ide/vscode/commons/boot/app/cli/SpringBootApp.java b/headless-services/commons/commons-boot-app-cli/src/main/java/org/springframework/ide/vscode/commons/boot/app/cli/SpringBootApp.java
index a6207d5dd..3a6daeaaa 100644
--- a/headless-services/commons/commons-boot-app-cli/src/main/java/org/springframework/ide/vscode/commons/boot/app/cli/SpringBootApp.java
+++ b/headless-services/commons/commons-boot-app-cli/src/main/java/org/springframework/ide/vscode/commons/boot/app/cli/SpringBootApp.java
@@ -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> 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> 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) {