From 8ef2e19fdf5f767990a9f2bd59805dc3d4e6d0a8 Mon Sep 17 00:00:00 2001 From: Kris De Volder Date: Tue, 21 Aug 2018 12:01:37 -0700 Subject: [PATCH] Add support for values of type java.time.Duration... So that both application.properties and application.yml - recognize/treat these as atomic values - can recognize 'garbage' values during reconcile and give a error. --- headless-services/commons/pom.xml | 1 + .../spring-boot-language-server/pom.xml | 25 +++++++------ .../vscode/boot/metadata/types/TypeUtil.java | 13 +++++++ .../test/ApplicationPropertiesEditorTest.java | 27 ++++++++++++++ .../boot/test/ApplicationYamlEditorTest.java | 35 +++++++++++++++++++ 5 files changed, 90 insertions(+), 11 deletions(-) diff --git a/headless-services/commons/pom.xml b/headless-services/commons/pom.xml index 595acd128..3810585f7 100644 --- a/headless-services/commons/pom.xml +++ b/headless-services/commons/pom.xml @@ -81,6 +81,7 @@ 2.10 0.4.0-SNAPSHOT 3.2.7 + 2.0.4.RELEASE 3.8.0.RELEASE 3.1.5.RELEASE diff --git a/headless-services/spring-boot-language-server/pom.xml b/headless-services/spring-boot-language-server/pom.xml index 7e6b985a0..4428158c2 100644 --- a/headless-services/spring-boot-language-server/pom.xml +++ b/headless-services/spring-boot-language-server/pom.xml @@ -1,17 +1,18 @@ - 4.0.0 spring-boot-language-server jar - + org.springframework.ide.vscode commons-parent 0.6.0-SNAPSHOT ../commons/pom.xml - + ${project.version} @@ -22,11 +23,11 @@ file://${project.basedir}/repo - + - + org.springframework.ide.eclipse org.json 1.0 @@ -61,11 +62,13 @@ commons-boot-app-cli ${dependencies.version} - + + org.springframework.boot + spring-boot + ${boot-version} + + org.eclipse.jdt org.eclipse.jdt.core @@ -132,6 +135,6 @@ - + diff --git a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/metadata/types/TypeUtil.java b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/metadata/types/TypeUtil.java index 658ac6049..6f35a5f16 100644 --- a/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/metadata/types/TypeUtil.java +++ b/headless-services/spring-boot-language-server/src/main/java/org/springframework/ide/vscode/boot/metadata/types/TypeUtil.java @@ -17,6 +17,7 @@ import static org.springframework.ide.vscode.commons.util.ArrayUtils.lastElement import java.net.InetAddress; import java.nio.charset.Charset; import java.text.SimpleDateFormat; +import java.time.Duration; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; @@ -34,6 +35,7 @@ import java.util.stream.Stream; import javax.inject.Provider; +import org.springframework.boot.convert.DurationStyle; import org.springframework.ide.vscode.boot.configurationmetadata.Deprecation; import org.springframework.ide.vscode.boot.java.links.SourceLinkFactory; import org.springframework.ide.vscode.boot.java.links.SourceLinks; @@ -58,6 +60,7 @@ import org.springframework.ide.vscode.commons.util.Log; import org.springframework.ide.vscode.commons.util.MimeTypes; import org.springframework.ide.vscode.commons.util.Renderables; import org.springframework.ide.vscode.commons.util.StringUtil; +import org.springframework.ide.vscode.commons.util.ValueParseException; import org.springframework.ide.vscode.commons.util.ValueParser; import com.google.common.collect.ImmutableList; @@ -95,6 +98,7 @@ public class TypeUtil { private static final Object OBJECT_TYPE_NAME = Object.class.getName(); private static final String STRING_TYPE_NAME = String.class.getName(); private static final String INET_ADDRESS_TYPE_NAME = InetAddress.class.getName(); + private static final String DURATION_TYPE_NAME = Duration.class.getName(); private static final String CLASS_TYPE_NAME = Class.class.getName(); public enum BeanPropertyNameMode { @@ -171,6 +175,7 @@ public class TypeUtil { "java.lang.Character", "java.lang.Byte", INET_ADDRESS_TYPE_NAME, + DURATION_TYPE_NAME, CLASS_TYPE_NAME, "java.lang.String[]" )); @@ -178,6 +183,7 @@ public class TypeUtil { private static final Set ATOMIC_TYPES = new HashSet<>(PRIMITIVE_TYPE_NAMES.keySet()); static { ATOMIC_TYPES.add(INET_ADDRESS_TYPE_NAME); + ATOMIC_TYPES.add(DURATION_TYPE_NAME); ATOMIC_TYPES.add(STRING_TYPE_NAME); ATOMIC_TYPES.add(CLASS_TYPE_NAME); } @@ -239,6 +245,13 @@ public class TypeUtil { throw new IllegalArgumentException("Value should be 'true' or 'false'"); } }); + VALUE_PARSERS.put(DURATION_TYPE_NAME, (s) -> { + try { + return DurationStyle.detectAndParse(s); + } catch (IllegalArgumentException e) { + throw new ValueParseException(e.getMessage()); + } + }); } public ValueParser getValueParser(Type type) { diff --git a/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/test/ApplicationPropertiesEditorTest.java b/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/test/ApplicationPropertiesEditorTest.java index 0007223ac..c56194ef0 100644 --- a/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/test/ApplicationPropertiesEditorTest.java +++ b/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/test/ApplicationPropertiesEditorTest.java @@ -78,6 +78,33 @@ public class ApplicationPropertiesEditorTest extends AbstractPropsEditorTest { editor.assertProblems("problem|extraneous input", "another|mismatched input"); } + + @Test public void bug_158348104() throws Exception { + //See: https://www.pivotaltracker.com/story/show/158348104 + data("spring.activemq.close-timeout", "java.time.Duration", null, null); + + Editor editor; + + editor = newEditor(""); + editor.assertContextualCompletions("springactcloti", + "spring.activemq.close-timeout=<*>" + ); + + editor = newEditor( + "spring.activemq.close-timeout=garbage" + ); + editor.assertProblems("garbage|not a valid duration"); + + editor = newEditor( + "spring.activemq.close-timeout: 15s" + ); + editor.assertProblems(/*NONE*/); + + editor = newEditor( + "spring.activemq.close-timeout: PT10S" //ISO duration format + ); + editor.assertProblems(/*NONE*/); + } @Test public void testServerPortCompletion() throws Exception { data("server.port", INTEGER, 8080, "Port where server listens for http."); assertCompletion("ser<*>", "server.port=<*>"); diff --git a/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/test/ApplicationYamlEditorTest.java b/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/test/ApplicationYamlEditorTest.java index 80826454c..e45d57fce 100644 --- a/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/test/ApplicationYamlEditorTest.java +++ b/headless-services/spring-boot-language-server/src/test/java/org/springframework/ide/vscode/boot/test/ApplicationYamlEditorTest.java @@ -51,6 +51,41 @@ public class ApplicationYamlEditorTest extends AbstractPropsEditorTest { //////////////////////////////////////////////////////////////////////////////////////// + @Test public void bug_158348104() throws Exception { + //See: https://www.pivotaltracker.com/story/show/158348104 + data("spring.activemq.close-timeout", "java.time.Duration", null, null); + + Editor editor; + + editor = newEditor(""); + editor.assertContextualCompletions("springactcloti", + "spring:\n" + + " activemq:\n" + + " close-timeout: <*>" + ); + + editor = newEditor( + "spring:\n" + + " activemq:\n" + + " close-timeout: garbage" + ); + editor.assertProblems("garbage|not a valid duration"); + + editor = newEditor( + "spring:\n" + + " activemq:\n" + + " close-timeout: 15s" + ); + editor.assertProblems(/*NONE*/); + + editor = newEditor( + "spring:\n" + + " activemq:\n" + + " close-timeout: PT10S" //ISO duration format + ); + editor.assertProblems(/*NONE*/); + } + @Test public void bug_153144391() throws Exception { //See: https://www.pivotaltracker.com/story/show/153144391 useProject(createPredefinedMavenProject("empty-boot-1.3.0-app"));