From 539afeca3a83871bea54ce4319062966c85d51ef Mon Sep 17 00:00:00 2001 From: nsingh Date: Tue, 14 Nov 2017 22:57:41 -0800 Subject: [PATCH] PT 152801833 - Added support for negative matches parsing for live conditionals --- .../ConditionalsLiveHoverProvider.java | 6 +- .../test/ConditionalsLiveHoverTest.java | 135 ++++++++++++++++-- .../harness/MockRunningAppProvider.java | 2 +- .../java/example/MultipleConditionals.java | 7 - .../commons/boot/app/cli/LiveConditional.java | 34 +++-- .../boot/app/cli/LiveConditionalParser.java | 114 +++++++++++---- .../commons/boot/app/cli/SpringBootApp.java | 2 +- 7 files changed, 239 insertions(+), 61 deletions(-) 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 d8db7c1f7..f938b1427 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 @@ -140,18 +140,18 @@ public class ConditionalsLiveHoverProvider implements HoverProvider { // Check that Java type in annotation in editor matches Java information in the live Conditional ASTNode parent = annotation.getParent(); - String rawJsonKey = liveConditional.getPositiveMatchKey(); + String typeInfo = liveConditional.getTypeInfo(); 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); + return typeInfo.contains(annotationDeclaringClassName) && typeInfo.contains(annotationMethodName); } else if (parent instanceof TypeDeclaration) { TypeDeclaration typeDec = (TypeDeclaration) parent; String annotationDeclaringClassName = typeDec.resolveBinding().getName(); - return rawJsonKey.contains(annotationDeclaringClassName); + return typeInfo.contains(annotationDeclaringClassName); } return false; } 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 f603e7122..2cf08d656 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 @@ -69,7 +69,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") - .positiveMatchesJsonForLiveConditionals( + .conditionalsJson( "{\"positiveMatches\":{\"ConditionalOnBeanConfig#hi\":[{\"condition\":\"OnBeanCondition\",\"message\":\"@ConditionalOnBean (types: example.Hello; SearchStrategy: all) found bean 'missing'\"}]}}") .build(); @@ -93,7 +93,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") - .positiveMatchesJsonForLiveConditionals( + .conditionalsJson( "{\"positiveMatches\":{\"ConditionalOnMissingBeanConfig#missing\":[{\"condition\":\"OnBeanCondition\",\"message\":\"@ConditionalOnMissingBean (types: example.Hello; SearchStrategy: all) did not find any beans\"}]}}") .build(); @@ -116,7 +116,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") - .positiveMatchesJsonForLiveConditionals( + .conditionalsJson( "{\"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(); @@ -158,19 +158,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") - .positiveMatchesJsonForLiveConditionals( + .conditionalsJson( "{\"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") - .positiveMatchesJsonForLiveConditionals( + .conditionalsJson( "{\"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") - .positiveMatchesJsonForLiveConditionals( + .conditionalsJson( "{\"positiveMatches\":{\"ConditionalOnMissingBeanConfig#missing\":[{\"condition\":\"OnBeanCondition\",\"message\":\"@ConditionalOnMissingBean (types: example.Hello; SearchStrategy: all) did not find any beans\"}]}}") .build(); @@ -218,7 +218,7 @@ 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") - .positiveMatchesJsonForLiveConditionals( + .conditionalsJson( "{\"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(); @@ -264,7 +264,7 @@ 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") - .positiveMatchesJsonForLiveConditionals( + .conditionalsJson( "{\"positiveMatches\":{\"MultipleConditionalsPT152535713#hi\":[{\"condition\":\"OnWebApplicationCondition\",\"message\":\"@ConditionalOnWebApplication (required) found StandardServletEnvironment\"},{\"condition\":\"OnJavaCondition\",\"message\":\"@ConditionalOnJava (1.8 or newer) found 1.8\"}]}}") .build(); @@ -290,7 +290,7 @@ public class ConditionalsLiveHoverTest { } @Test - public void testHighlights() throws Exception { + public void testHighlightsMethodConditionals() throws Exception { File directory = new File( ProjectsHarness.class.getResource("/test-projects/test-conditionals-live-hover/").toURI()); @@ -299,18 +299,131 @@ 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") - .positiveMatchesJsonForLiveConditionals( + .conditionalsJson( "{\"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(); harness.intialize(directory); + String content = "package example;\n" + + "\n" + + "import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;\n" + + "import org.springframework.boot.autoconfigure.condition.ConditionalOnExpression;\n" + + "import org.springframework.boot.autoconfigure.condition.ConditionalOnJava;\n" + + "import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;\n" + + "import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingClass;\n" + + "import org.springframework.boot.autoconfigure.condition.ConditionalOnNotWebApplication;\n" + + "import org.springframework.boot.autoconfigure.condition.ConditionalOnWebApplication;\n" + + "import org.springframework.context.annotation.Bean;\n" + + "import org.springframework.context.annotation.Configuration;\n" + + "\n" + + "@Configuration\n" + + "public class MultipleConditionals {\n" + + "\n" + + " @Bean\n" + + " @ConditionalOnBean\n" + + " @ConditionalOnWebApplication\n" + + " @ConditionalOnJava(value=ConditionalOnJava.JavaVersion.EIGHT)\n" + + " @ConditionalOnMissingClass\n" + + " @ConditionalOnExpression\n" + + " public Hello hi() {\n" + + " return null;\n" + + " }\n" + + "}"; - Editor editor = harness.newEditorFromFileUri(docUri, LanguageId.JAVA); + Editor editor = harness.newEditor( LanguageId.JAVA, content, docUri); editor.assertHighlights("@ConditionalOnBean", "@ConditionalOnWebApplication", "@ConditionalOnJava(value=ConditionalOnJava.JavaVersion.EIGHT)", "@ConditionalOnMissingClass", "@ConditionalOnExpression"); } + + @Test + public void testHighlightsTypeConditionals() throws Exception { + + File directory = new File( + ProjectsHarness.class.getResource("/test-projects/test-conditionals-live-hover/").toURI()); + String docUri = "file://" + directory.getAbsolutePath() + "/src/main/java/example/MultipleConditionals.java"; + + // Build a mock running boot app + mockAppProvider.builder().isSpringBootApp(true).port("1111").processId("22022").host("cfapps.io") + .processName("test-conditionals-live-hover") + .conditionalsJson( + "{\"negativeMatches\": {\n" + + " \"MyConditionalComponent\": {\n" + + " \"notMatched\": [\n" + + " {\n" + + " \"condition\": \"OnClassCondition\",\n" + + " \"message\": \"@ConditionalOnClass did not find required class 'java.lang.String2'\"\n" + + " }\n" + + " ],\n" + + " \"matched\": []\n" + + " }\n" + + "}\n" + + "}") + .build(); + + harness.intialize(directory); + + String content = "package com.example;\n" + + "\n" + + "import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\n" + + "import org.springframework.stereotype.Component;\n" + + "\n" + + "@Component\n" + + "@ConditionalOnClass(name=\"java.lang.String2\")\n" + + "public class MyConditionalComponent {\n" + + "}"; + + Editor editor = harness.newEditor( LanguageId.JAVA, content, docUri); + + editor.assertHighlights("@ConditionalOnClass(name=\"java.lang.String2\")"); + + } + + @Test + public void testNegativeMatches() throws Exception { + + File directory = new File( + ProjectsHarness.class.getResource("/test-projects/test-conditionals-live-hover/").toURI()); + String docUri = "file://" + directory.getAbsolutePath() + "/src/main/java/example/MultipleConditionals.java"; + + // Build a mock running boot app + mockAppProvider.builder().isSpringBootApp(true).port("1111").processId("67950").host("cfapps.io") + .processName("test-conditionals-live-hover") + .conditionalsJson( + "{\"negativeMatches\": {\n" + + " \"MyConditionalComponent\": {\n" + + " \"notMatched\": [\n" + + " {\n" + + " \"condition\": \"OnClassCondition\",\n" + + " \"message\": \"@ConditionalOnClass did not find required class 'java.lang.String2'\"\n" + + " }\n" + + " ],\n" + + " \"matched\": []\n" + + " }\n" + + "}\n" + + "}") + .build(); + + harness.intialize(directory); + + String content = "package com.example;\n" + + "\n" + + "import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;\n" + + "import org.springframework.stereotype.Component;\n" + + "\n" + + "@Component\n" + + "@ConditionalOnClass(name=\"java.lang.String2\")\n" + + "public class MyConditionalComponent {\n" + + "}"; + + Editor editor = harness.newEditor( LanguageId.JAVA, content, docUri); + + editor.assertHoverContains("@ConditionalOnClass(name=\"java.lang.String2\")", "@ConditionalOnClass did not find required class 'java.lang.String2'\n" + + "\n" + + "Process [PID=67950, name=`test-conditionals-live-hover`]"); + + } } 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 f5c6aaade..ba45ad460 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 @@ -116,7 +116,7 @@ public class MockRunningAppProvider { return this; } - public MockAppBuilder positiveMatchesJsonForLiveConditionals(String rawJson) throws Exception{ + public MockAppBuilder conditionalsJson(String rawJson) throws Exception{ when(app.getLiveConditionals()).thenReturn(SpringBootApp.getLiveConditionals(rawJson, processId, processName)); return this; } diff --git a/headless-services/boot-java-language-server/src/test/resources/test-projects/test-conditionals-live-hover/src/main/java/example/MultipleConditionals.java b/headless-services/boot-java-language-server/src/test/resources/test-projects/test-conditionals-live-hover/src/main/java/example/MultipleConditionals.java index 4417dc166..b4257ec43 100644 --- a/headless-services/boot-java-language-server/src/test/resources/test-projects/test-conditionals-live-hover/src/main/java/example/MultipleConditionals.java +++ b/headless-services/boot-java-language-server/src/test/resources/test-projects/test-conditionals-live-hover/src/main/java/example/MultipleConditionals.java @@ -22,11 +22,4 @@ public class MultipleConditionals { public Hello hi() { return null; } - - @Bean - @ConditionalOnMissingBean - @ConditionalOnNotWebApplication - public Hello missing() { - return null; - } } 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 index 3f4432838..037c05841 100644 --- 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 @@ -16,7 +16,7 @@ public class LiveConditional { private String message; private String processId; private String processName; - private String positiveMatchKey; + private String typeInfo; public LiveConditional() { @@ -38,8 +38,8 @@ public class LiveConditional { return processName; } - public String getPositiveMatchKey() { - return positiveMatchKey; + public String getTypeInfo() { + return typeInfo; } public static class LiveConditionalBuilder { @@ -67,13 +67,31 @@ public class LiveConditional { } /** - * 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 + * Type information for which a conditional is applied to. + *

+ * + * Example: + *

+ * For this class: + *

+ * "@ConditionalOnClass(name="java.lang.String2") + * public class MyConditionalComponent { + * }" + *

+ * This is the "real" autoconfig JSON: + *

+ * "negativeMatches": { "MyConditionalComponent": { "notMatched": [ { + * "condition": "OnClassCondition", "message": "@ConditionalOnClass did not find + * required class 'java.lang.String2'" } ], "matched": [] } + *

+ * In this example, "MyConditionalComponent" information in the JSON indicates the type where the conditional is being applied to. + *

+ * Type info can also contain method information if a conditional annotation is applied to a method. Example: MyConditionalComponent#myBean) + * @param typeInfo * @return */ - public LiveConditionalBuilder positiveMatchKey(String positiveMatchKey) { - conditional.positiveMatchKey = positiveMatchKey; + public LiveConditionalBuilder typeInfo(String typeInfo) { + conditional.typeInfo = typeInfo; return this; } 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 index e871989fd..af45b2956 100644 --- 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 @@ -50,6 +50,8 @@ public class LiveConditionalParser { if (StringUtil.hasText(autoConfigRecord)) { getConditionalsFromPositiveMatches(autoConfigRecord).stream() .forEach(conditional -> allConditionals.add(conditional)); + getConditionalsFromNegativeMatches(autoConfigRecord).stream() + .forEach(conditional -> allConditionals.add(conditional)); } if (!allConditionals.isEmpty()) { return Optional.of(allConditionals); @@ -61,9 +63,7 @@ public class LiveConditionalParser { } /** - * Fetches the "positiveMatches" element in the autoconfig report that contains conditional information. - * @param positiveMatchKey - * @return + * Fetches the "positiveMatches" element in the autoconfig report JSON that contains conditional information. */ private Optional getPositiveMatchesJson(String autoConfigReport) { JSONObject autoConfigJson = new JSONObject(autoConfigReport); @@ -83,46 +83,100 @@ public class LiveConditionalParser { return Optional.empty(); } + /** + * Fetches the "negativeMatches" element in the autoconfig report JSON that contains conditional information. + */ + private Optional getNegativeMatchesJson(String autoConfigReport) { + JSONObject autoConfigJson = new JSONObject(autoConfigReport); + + Iterator keys = autoConfigJson.keys(); + + while (keys.hasNext()) { + String key = keys.next(); + if ("negativeMatches".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) { + private List getConditionalsFromPositiveMatches(String autoConfigReport) { List conditions = new ArrayList<>(); - - getPositiveMatchesJson(autoconfigReport).ifPresent((positiveMatches) -> { - Iterator pMKeys = positiveMatches.keys(); - while (pMKeys.hasNext()) { + getPositiveMatchesJson(autoConfigReport).ifPresent((matches) -> { + matches.keySet().stream().forEach(typeInfo -> { // 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)); - } - }); - } - }); + Object val = matches.get(typeInfo); + if (val instanceof JSONArray) { + JSONArray contentList = (JSONArray) val; + parseConditionalsFromContentList(conditions, typeInfo, contentList); + } + }); + }); 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(); + private List getConditionalsFromNegativeMatches(String autoConfigReport) { + List conditions = new ArrayList<>(); + // The JSON structure being parsed is: +// "negativeMatches": { +// "MyConditionalComponent": { +// "notMatched": [ +// { +// "condition": "OnClassCondition", +// "message": "@ConditionalOnClass did not find required class 'java.lang.String2'" +// } +// ], +// "matched": [] +// } + getNegativeMatchesJson(autoConfigReport).ifPresent((matches) -> { + // The key in the "matches" JSON contains the live type information where the conditional was applied to + matches.keySet().stream().forEach(typeInfo -> { + // The positive match key contains the bean method information where conditional + // was applied to + Object val = matches.get(typeInfo); + if (val instanceof JSONObject) { + JSONObject negativeMatches = (JSONObject) val; + negativeMatches.keySet().stream().forEach((key) -> { + JSONArray contentList = (JSONArray) negativeMatches.get(key); + parseConditionalsFromContentList(conditions, typeInfo, contentList); + }); + } + }); + + }); + return conditions; } + private void parseConditionalsFromContentList(List conditionals, String typeInfo, + JSONArray contentList) { + contentList.forEach((content) -> { + if (content instanceof JSONObject) { + JSONObject conditionalJson = (JSONObject) content; + 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)) { + LiveConditional conditional = LiveConditional.builder().processId(appProcessId) + .processName(appProcessName).condition(condition).message(message).typeInfo(typeInfo) + .build(); + conditionals.add(conditional); + } + } + }); + } + + 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 32aca0891..0a670bdd7 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 @@ -251,7 +251,7 @@ public class SpringBootApp { */ public static Optional> getLiveConditionals(String autoConfigReport, String processId, String processName) { - return new LiveConditionalParser(autoConfigReport, processId, processName).parse(); + return LiveConditionalParser.parse(autoConfigReport, processId, processName); } public String getAutoConfigReport() throws Exception {