diff --git a/plugin/src/main/java/io/jenkins/plugins/casc/impl/configurators/DataBoundConfigurator.java b/plugin/src/main/java/io/jenkins/plugins/casc/impl/configurators/DataBoundConfigurator.java
index dae7fa9d72..ead17eaff8 100644
--- a/plugin/src/main/java/io/jenkins/plugins/casc/impl/configurators/DataBoundConfigurator.java
+++ b/plugin/src/main/java/io/jenkins/plugins/casc/impl/configurators/DataBoundConfigurator.java
@@ -11,6 +11,7 @@
import io.jenkins.plugins.casc.impl.attributes.DescribableAttribute;
import io.jenkins.plugins.casc.model.CNode;
import io.jenkins.plugins.casc.model.Mapping;
+import java.lang.reflect.Array;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
@@ -301,8 +302,23 @@ public CNode describe(T instance, ConfigurationContext context) throws Exception
if (a != null) {
Object value = a.getValue(instance);
if (value != null) {
- Object converted = Stapler.CONVERT_UTILS.convert(value, a.getType());
- if (converted instanceof Collection || p.getType().isArray() || !a.isMultiple()) {
+ Class> targetType = a.getType();
+ Object converted = Stapler.CONVERT_UTILS.convert(value, targetType);
+
+ if (p.getType().isArray() && converted instanceof Collection> col) {
+ Class> component = p.getType().getComponentType();
+ Object array = Array.newInstance(component, col.size());
+ int idx = 0;
+ for (Object o : col) {
+ Array.set(array, idx++, o);
+ }
+ args[i] = array;
+
+ } else if (Set.class.isAssignableFrom(p.getType()) && converted instanceof Collection) {
+ args[i] = new HashSet<>((Collection>) converted);
+ } else if (converted instanceof Collection
+ || (converted != null && converted.getClass().isArray())
+ || !a.isMultiple()) {
args[i] = converted;
} else if (Set.class.isAssignableFrom(p.getType())) {
args[i] = Collections.singleton(converted);
diff --git a/test-harness/src/test/java/io/jenkins/plugins/casc/impl/configurators/DataBoundConfiguratorTest.java b/test-harness/src/test/java/io/jenkins/plugins/casc/impl/configurators/DataBoundConfiguratorTest.java
index 06fdedeba2..fe83a3ab61 100644
--- a/test-harness/src/test/java/io/jenkins/plugins/casc/impl/configurators/DataBoundConfiguratorTest.java
+++ b/test-harness/src/test/java/io/jenkins/plugins/casc/impl/configurators/DataBoundConfiguratorTest.java
@@ -12,6 +12,7 @@
import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.kohsuke.stapler.Stapler.CONVERT_UTILS;
import hudson.util.Secret;
import io.jenkins.plugins.casc.ConfigurationAsCode;
@@ -30,12 +31,18 @@
import io.jenkins.plugins.casc.model.Sequence;
import java.io.PrintWriter;
import java.io.StringWriter;
+import java.util.Arrays;
+import java.util.Collection;
import java.util.HashSet;
+import java.util.List;
+import java.util.Objects;
import java.util.Set;
+import java.util.concurrent.atomic.AtomicInteger;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.annotation.ParametersAreNonnullByDefault;
import javax.annotation.PostConstruct;
+import org.apache.commons.beanutils.Converter;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
@@ -45,6 +52,7 @@
import org.jvnet.hudson.test.junit.jupiter.WithJenkins;
import org.kohsuke.stapler.DataBoundConstructor;
import org.kohsuke.stapler.DataBoundSetter;
+import org.kohsuke.stapler.Stapler;
/**
* @author Nicolas De Loof
@@ -426,4 +434,484 @@ public ArrayConstructor(Foo[] anArray) {
this.anArray = anArray;
}
}
+
+ @SuppressWarnings("ClassCanBeRecord")
+ public static class CustomItem {
+ private final String value;
+
+ @DataBoundConstructor
+ public CustomItem(String value) {
+ this.value = value;
+ }
+
+ public String getValue() {
+ return value;
+ }
+ }
+
+ @SuppressWarnings("ClassCanBeRecord")
+ public static class CustomItemListHolder {
+ private final List items;
+
+ @DataBoundConstructor
+ public CustomItemListHolder(List items) {
+ this.items = items;
+ }
+
+ public List getItems() {
+ return items;
+ }
+ }
+
+ @Test
+ @Issue("https://github.com/jenkinsci/configuration-as-code-plugin/issues/2346")
+ void exportWithCustomConverterIteratesOverList() throws Exception {
+ List list = Arrays.asList(new CustomItem("A"), new CustomItem("B"));
+ CustomItemListHolder holder = new CustomItemListHolder(list);
+
+ ConfiguratorRegistry registry = ConfiguratorRegistry.get();
+ final Configurator