From 487e268f4bfcad548814bfe8e4caa2c94c14eef3 Mon Sep 17 00:00:00 2001 From: Carlos Tasada Date: Sat, 6 Apr 2024 19:28:29 +0200 Subject: [PATCH] feat: Added support for arrays to the Generic Binding (#679) * chore: Added support for arrays to the Generic Binding When using the Generic Binding, it was not possible to define an array value. Here we add support for it. Example: "key=[value1, value2, value3]" * Improved regexp and fix comments * Add test with spaces * Improved parsing to ignore "broken" arrays --- .../springwolf-generic-binding/build.gradle | 1 + .../annotation/processor/PropertiesUtil.java | 29 ++++++-- ...cGenericOperationBindingProcessorTest.java | 68 ++++++++++++++++++- 3 files changed, 90 insertions(+), 8 deletions(-) diff --git a/springwolf-add-ons/springwolf-generic-binding/build.gradle b/springwolf-add-ons/springwolf-generic-binding/build.gradle index 7d8dba5fd..d0fbe1ee7 100644 --- a/springwolf-add-ons/springwolf-generic-binding/build.gradle +++ b/springwolf-add-ons/springwolf-generic-binding/build.gradle @@ -21,6 +21,7 @@ dependencies { testImplementation "org.assertj:assertj-core:${assertjCoreVersion}" testImplementation "org.junit.jupiter:junit-jupiter-api:${junitJupiterVersion}" + testImplementation("org.junit.jupiter:junit-jupiter-params:${junitJupiterVersion}") testRuntimeOnly "org.junit.jupiter:junit-jupiter:${junitJupiterVersion}" } diff --git a/springwolf-add-ons/springwolf-generic-binding/src/main/java/io/github/springwolf/addons/generic_binding/annotation/processor/PropertiesUtil.java b/springwolf-add-ons/springwolf-generic-binding/src/main/java/io/github/springwolf/addons/generic_binding/annotation/processor/PropertiesUtil.java index 7a4b1c96e..ea6e828eb 100644 --- a/springwolf-add-ons/springwolf-generic-binding/src/main/java/io/github/springwolf/addons/generic_binding/annotation/processor/PropertiesUtil.java +++ b/springwolf-add-ons/springwolf-generic-binding/src/main/java/io/github/springwolf/addons/generic_binding/annotation/processor/PropertiesUtil.java @@ -10,10 +10,16 @@ import java.util.LinkedList; import java.util.Map; import java.util.Properties; +import java.util.regex.Matcher; +import java.util.regex.Pattern; @Slf4j public class PropertiesUtil { + private static final Pattern ARRAY_PATTERN = Pattern.compile("^\\[([^]]+)]$"); + + private PropertiesUtil() {} + public static Map toMap(String[] propertyStrings) { return convertPropertiesToNestedMap(buildPropertiesFrom((propertyStrings))); } @@ -39,17 +45,30 @@ private static Map convertPropertiesToNestedMap(Properties prope Map mapNode = bindingData; while (path.size() > 1) { String pathElement = path.get(0); - if (!mapNode.containsKey(pathElement)) { - mapNode.put(pathElement, new HashMap<>()); - } - + mapNode.computeIfAbsent(pathElement, k -> new HashMap<>()); mapNode = (Map) mapNode.get(pathElement); path.pop(); } - mapNode.put(path.get(0), properties.get(propertyName)); + var value = parseValue(properties.get(propertyName)); + mapNode.put(path.get(0), value); } return bindingData; } + + private static Object parseValue(Object input) { + if (input instanceof String inputString) { + Matcher matcher = ARRAY_PATTERN.matcher(inputString); + + // Check if the pattern matches the input string + if (matcher.find()) { + // Extract the key and values + String[] values = matcher.group(1).split(","); + return Arrays.stream(values).map(String::trim).toList(); + } + } + + return input; + } } diff --git a/springwolf-add-ons/springwolf-generic-binding/src/test/java/io/github/springwolf/addons/generic_binding/annotation/processor/AsyncGenericOperationBindingProcessorTest.java b/springwolf-add-ons/springwolf-generic-binding/src/test/java/io/github/springwolf/addons/generic_binding/annotation/processor/AsyncGenericOperationBindingProcessorTest.java index fd534d9f9..cfdae8702 100644 --- a/springwolf-add-ons/springwolf-generic-binding/src/test/java/io/github/springwolf/addons/generic_binding/annotation/processor/AsyncGenericOperationBindingProcessorTest.java +++ b/springwolf-add-ons/springwolf-generic-binding/src/test/java/io/github/springwolf/addons/generic_binding/annotation/processor/AsyncGenericOperationBindingProcessorTest.java @@ -5,6 +5,8 @@ import io.github.springwolf.core.asyncapi.scanners.bindings.operations.ProcessedOperationBinding; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; +import org.junit.jupiter.params.ParameterizedTest; +import org.junit.jupiter.params.provider.CsvSource; import java.util.Arrays; import java.util.List; @@ -22,7 +24,7 @@ void testClassWithoutAnnotation() { List result = getProcessedOperationBindings(ClassWithoutAnnotation.class); // then - assertThat(result).hasSize(0); + assertThat(result).isEmpty(); } @Test @@ -41,12 +43,11 @@ void testClassWithAnnotationHasABinding() { } private List getProcessedOperationBindings(Class testClass) { - List result = Arrays.stream(testClass.getDeclaredMethods()) + return Arrays.stream(testClass.getDeclaredMethods()) .map((m) -> m.getAnnotationsByType(AsyncGenericOperationBinding.class)) .flatMap(Arrays::stream) .map(processor::mapToOperationBinding) .toList(); - return result; } private static class ClassWithoutAnnotation { @@ -89,6 +90,18 @@ void onePropertyTest() { assertThat(result).isEqualTo(Map.of("key", "value")); } + @Test + void oneLongPropertyTest() { + // given + String[] strings = {"key=value is long"}; + + // when + Map result = PropertiesUtil.toMap(strings); + + // then + assertThat(result).isEqualTo(Map.of("key", "value is long")); + } + @Test void twoPropertiesTest() { // given @@ -101,6 +114,43 @@ void twoPropertiesTest() { assertThat(result).isEqualTo(Map.of("key1", "value1", "key2", "value2")); } + @Test + void arrayPropertyTest() { + // given + String[] strings = {"key=[value1, value2, value3 is long]"}; + + // when + Map result = PropertiesUtil.toMap(strings); + + // then + assertThat(result).isEqualTo(Map.of("key", List.of("value1", "value2", "value3 is long"))); + } + + @CsvSource(value = {"asdf[sdf]", "[sdf][sdf]", "[sd[sdf]]", "[kdkd]dkkd", "[kdkd"}) + @ParameterizedTest + void arrayParsingShouldBeIgnored(String value) { + // given + String[] strings = {"key=" + value}; + + // when + Map result = PropertiesUtil.toMap(strings); + + // then value is still a string, ignoring the array conversion + assertThat(result).isEqualTo(Map.of("key", value)); + } + + @Test + void simpleMapPropertyTest() { + // given + String[] strings = {"map.key1=value1", "map.key2=value2", "map.key3=value3"}; + + // when + Map result = PropertiesUtil.toMap(strings); + + // then + assertThat(result).isEqualTo(Map.of("map", Map.of("key1", "value1", "key2", "value2", "key3", "value3"))); + } + @Test void nestedPropertyTest() { // given @@ -136,5 +186,17 @@ void yamlSyntaxDoesWorkAsWell() { // then assertThat(result).isEqualTo(Map.of("key", "value")); } + + @Test + void yamlSyntaxArrayPropertyTest() { + // given + String[] strings = {"key: [value1, value2, value3 is long]"}; + + // when + Map result = PropertiesUtil.toMap(strings); + + // then + assertThat(result).isEqualTo(Map.of("key", List.of("value1", "value2", "value3 is long"))); + } } }