diff --git a/plugin/src/main/java/io/jenkins/plugins/casc/BaseConfigurator.java b/plugin/src/main/java/io/jenkins/plugins/casc/BaseConfigurator.java index 7bc7f30419..2649b31bb2 100644 --- a/plugin/src/main/java/io/jenkins/plugins/casc/BaseConfigurator.java +++ b/plugin/src/main/java/io/jenkins/plugins/casc/BaseConfigurator.java @@ -29,9 +29,12 @@ import java.util.Collections; import java.util.HashMap; import java.util.HashSet; +import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.SortedSet; +import java.util.TreeSet; import java.util.logging.Level; import java.util.logging.Logger; import java.util.stream.Collectors; @@ -169,14 +172,23 @@ public abstract class BaseConfigurator implements Configurator { rawAttribute.setter((targetInstance, value) -> { Object finalValue = value; - if (value instanceof Collection collection && finalType.rawType.isArray()) { - Object array = newInstance(rawAttribute.getType(), collection.size()); - int i = 0; - for (Object item : collection) { - set(array, i++, item); + if (value instanceof Collection collection) { + if (finalType.rawType.isArray()) { + Object array = newInstance(rawAttribute.getType(), collection.size()); + int i = 0; + for (Object item : collection) { + set(array, i++, item); + } + finalValue = array; + + } else if (SortedSet.class.isAssignableFrom(finalType.rawType)) { + finalValue = new TreeSet<>(collection); + + } else if (Set.class.isAssignableFrom(finalType.rawType)) { + finalValue = new LinkedHashSet<>(collection); } - finalValue = array; } + bestMethod.invoke(targetInstance, finalValue); }); diff --git a/plugin/src/test/java/io/jenkins/plugins/casc/BaseConfiguratorTest.java b/plugin/src/test/java/io/jenkins/plugins/casc/BaseConfiguratorTest.java index f80c34de81..92e708f01b 100644 --- a/plugin/src/test/java/io/jenkins/plugins/casc/BaseConfiguratorTest.java +++ b/plugin/src/test/java/io/jenkins/plugins/casc/BaseConfiguratorTest.java @@ -11,9 +11,12 @@ import io.jenkins.plugins.casc.model.Mapping; import java.lang.reflect.Method; import java.util.Arrays; +import java.util.LinkedHashSet; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.SortedSet; +import java.util.TreeSet; import java.util.stream.Collectors; import org.junit.Test; import org.kohsuke.accmod.Restricted; @@ -58,6 +61,8 @@ public static class Z_Class {} public static class DummyTarget { private String[] items; + private Set stringSet; + private SortedSet sortedStringSet; public String getStandard() { return null; @@ -109,6 +114,22 @@ public void setItems(String[] items) { this.items = items; } + public Set getStringSet() { + return stringSet; + } + + public void setStringSet(Set stringSet) { + this.stringSet = stringSet; + } + + public SortedSet getSortedStringSet() { + return sortedStringSet; + } + + public void setSortedStringSet(SortedSet sortedStringSet) { + this.sortedStringSet = sortedStringSet; + } + public List getArrayFallback() { return null; } @@ -269,7 +290,7 @@ public void testDescribeResolvesBestSetters() { Map> resolvedAttributes = attributes.stream().collect(Collectors.toMap(Attribute::getName, attr -> (Class) attr.getType())); - assertEquals("Should discover exactly 22 configurable properties", 22, resolvedAttributes.size()); + assertEquals("Should discover exactly 24 configurable properties", 24, resolvedAttributes.size()); assertEquals("Standard setter should resolve to String", String.class, resolvedAttributes.get("standard")); @@ -363,6 +384,8 @@ public void testDescribeResolvesBestSetters() { "ambiguous", "mismatchedToken", "items", + "stringSet", + "sortedStringSet", "arrayFallback", "shapeSubtype", "concreteWins", @@ -405,6 +428,40 @@ public void testCollectionToArrayConversion() throws Exception { assertArrayEquals(new String[] {"foo", "bar", "baz"}, result); } + @Test + @SuppressWarnings({"unchecked", "rawtypes"}) + public void testCollectionToSetConversions() throws Exception { + DummyConfigurator configurator = new DummyConfigurator(); + Set> attributes = configurator.describe(); + + Attribute setAttr = attributes.stream() + .filter(a -> a.getName().equals("stringSet")) + .findFirst() + .orElseThrow(() -> new AssertionError("stringSet attribute not found")); + + Attribute sortedSetAttr = attributes.stream() + .filter(a -> a.getName().equals("sortedStringSet")) + .findFirst() + .orElseThrow(() -> new AssertionError("sortedStringSet attribute not found")); + + DummyTarget target = new DummyTarget(); + + List inputCollection = Arrays.asList("foo", "bar", "baz"); + + ((Attribute) setAttr).setValue(target, inputCollection); + ((Attribute) sortedSetAttr).setValue(target, inputCollection); + + Set setResult = target.getStringSet(); + assertNotNull("Set should have been populated", setResult); + assertEquals("Set should be converted to LinkedHashSet", LinkedHashSet.class, setResult.getClass()); + assertEquals("Set should have 3 items", 3, setResult.size()); + + SortedSet sortedSetResult = target.getSortedStringSet(); + assertNotNull("SortedSet should have been populated", sortedSetResult); + assertEquals("SortedSet should be converted to TreeSet", TreeSet.class, sortedSetResult.getClass()); + assertEquals("SortedSet should have 3 items", 3, sortedSetResult.size()); + } + @Test public void testFindGetterReturnsNullForMissingOrInvalidGetters() { NoGetterConfigurator configurator = new NoGetterConfigurator();