From e7ccad5757ebf9af7e49cb5d1b7efb61034e11ca Mon Sep 17 00:00:00 2001
From: Naveed Khan
Date: Thu, 23 Jul 2026 15:06:55 +0530
Subject: [PATCH 1/6] disable comment char in ArrayConverter list parsing
parseElements left StreamTokenizer's default comment character '/' active, so a list element containing a slash commented out the rest of the input and dropped the following elements. Treat '/' as an ordinary separator instead.
---
.../beanutils2/converters/ArrayConverter.java | 1 +
.../converters/ArrayConverterTest.java | 17 +++++++++++++++++
2 files changed, 18 insertions(+)
diff --git a/src/main/java/org/apache/commons/beanutils2/converters/ArrayConverter.java b/src/main/java/org/apache/commons/beanutils2/converters/ArrayConverter.java
index bfcc4e4e7..e2c1c112b 100644
--- a/src/main/java/org/apache/commons/beanutils2/converters/ArrayConverter.java
+++ b/src/main/java/org/apache/commons/beanutils2/converters/ArrayConverter.java
@@ -340,6 +340,7 @@ private List parseElements(String value) {
st.whitespaceChars(delimiter, delimiter); // Set the delimiters
st.ordinaryChars('0', '9'); // Needed to turn off numeric flag
st.wordChars('0', '9'); // Needed to make part of tokens
+ st.ordinaryChar('/'); // Turn off the default comment character so it splits like any other separator
for (final char allowedChar : allowedChars) {
st.ordinaryChars(allowedChar, allowedChar);
st.wordChars(allowedChar, allowedChar);
diff --git a/src/test/java/org/apache/commons/beanutils2/converters/ArrayConverterTest.java b/src/test/java/org/apache/commons/beanutils2/converters/ArrayConverterTest.java
index 5779e83fa..fcf0c1926 100644
--- a/src/test/java/org/apache/commons/beanutils2/converters/ArrayConverterTest.java
+++ b/src/test/java/org/apache/commons/beanutils2/converters/ArrayConverterTest.java
@@ -248,6 +248,23 @@ void testTheMatrix() {
}
}
+ /**
+ * A forward slash is not an allowed character, so it must split like any other separator (see {@link #testUnderscore_BEANUTILS_302()}) instead of commenting
+ * out the rest of the input and dropping the remaining elements.
+ */
+ @Test
+ void testForwardSlashSeparator() {
+ final String value = "first/value,second/value";
+ final ArrayConverter converter = new ArrayConverter(String[].class, new StringConverter());
+ final String[] result = converter.convert(String[].class, value);
+ assertNotNull(result, "result.null");
+ assertEquals(4, result.length, "result.length");
+ assertEquals("first", result[0], "result[0]");
+ assertEquals("value", result[1], "result[1]");
+ assertEquals("second", result[2], "result[2]");
+ assertEquals("value", result[3], "result[3]");
+ }
+
/**
* Test for BEANUTILS-302 - throwing a NPE when underscore used
*/
From f41f0e4331cca0eb7e516aa020c017d270cedd3c Mon Sep 17 00:00:00 2001
From: Gary Gregory
Date: Thu, 23 Jul 2026 07:52:34 -0400
Subject: [PATCH 2/6] Potential fix for pull request finding
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
---
.../commons/beanutils2/converters/ArrayConverterTest.java | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/src/test/java/org/apache/commons/beanutils2/converters/ArrayConverterTest.java b/src/test/java/org/apache/commons/beanutils2/converters/ArrayConverterTest.java
index fcf0c1926..1ea2e84fd 100644
--- a/src/test/java/org/apache/commons/beanutils2/converters/ArrayConverterTest.java
+++ b/src/test/java/org/apache/commons/beanutils2/converters/ArrayConverterTest.java
@@ -255,7 +255,7 @@ void testTheMatrix() {
@Test
void testForwardSlashSeparator() {
final String value = "first/value,second/value";
- final ArrayConverter converter = new ArrayConverter(String[].class, new StringConverter());
+ final ArrayConverter converter = new ArrayConverter<>(String[].class, new StringConverter());
final String[] result = converter.convert(String[].class, value);
assertNotNull(result, "result.null");
assertEquals(4, result.length, "result.length");
From 5f340ebe6a6510e4d82caf744269825ff3818c05 Mon Sep 17 00:00:00 2001
From: Naveed Khan
Date: Thu, 23 Jul 2026 21:19:11 +0530
Subject: [PATCH 3/6] cover allowed-chars behavior for forward slash in test
---
.../beanutils2/converters/ArrayConverterTest.java | 11 ++++++++++-
1 file changed, 10 insertions(+), 1 deletion(-)
diff --git a/src/test/java/org/apache/commons/beanutils2/converters/ArrayConverterTest.java b/src/test/java/org/apache/commons/beanutils2/converters/ArrayConverterTest.java
index 1ea2e84fd..0595bac06 100644
--- a/src/test/java/org/apache/commons/beanutils2/converters/ArrayConverterTest.java
+++ b/src/test/java/org/apache/commons/beanutils2/converters/ArrayConverterTest.java
@@ -256,13 +256,22 @@ void testTheMatrix() {
void testForwardSlashSeparator() {
final String value = "first/value,second/value";
final ArrayConverter converter = new ArrayConverter<>(String[].class, new StringConverter());
- final String[] result = converter.convert(String[].class, value);
+ // test forward slash not allowed (the default)
+ String[] result = converter.convert(String[].class, value);
assertNotNull(result, "result.null");
assertEquals(4, result.length, "result.length");
assertEquals("first", result[0], "result[0]");
assertEquals("value", result[1], "result[1]");
assertEquals("second", result[2], "result[2]");
assertEquals("value", result[3], "result[3]");
+ // configure the converter to allow forward slash
+ converter.setAllowedChars(new char[] { '.', '-', '/' });
+ // test forward slash allowed
+ result = converter.convert(String[].class, value);
+ assertNotNull(result, "result.null");
+ assertEquals(2, result.length, "result.length");
+ assertEquals("first/value", result[0], "result[0]");
+ assertEquals("second/value", result[1], "result[1]");
}
/**
From 4fe65c3cfabb33c0b850ae4390d523a44931c699 Mon Sep 17 00:00:00 2001
From: Naveed Khan
Date: Mon, 27 Jul 2026 20:33:44 +0530
Subject: [PATCH 4/6] add missing @Test annotation to testForwardSlashSeparator
---
.../apache/commons/beanutils2/converters/ArrayConverterTest.java | 1 +
1 file changed, 1 insertion(+)
diff --git a/src/test/java/org/apache/commons/beanutils2/converters/ArrayConverterTest.java b/src/test/java/org/apache/commons/beanutils2/converters/ArrayConverterTest.java
index 6f7be51f4..8cd693f96 100644
--- a/src/test/java/org/apache/commons/beanutils2/converters/ArrayConverterTest.java
+++ b/src/test/java/org/apache/commons/beanutils2/converters/ArrayConverterTest.java
@@ -163,6 +163,7 @@ void testErrors() {
assertThrows(NullPointerException.class, () -> new ArrayConverter(int[].class, null));
}
+ @Test
void testForwardSlashSeparator() {
final String value = "first/value,second/value";
final ArrayConverter converter = new ArrayConverter<>(String[].class, new StringConverter());
From a0d56b8875463adfd81e7e73bd662013786c5292 Mon Sep 17 00:00:00 2001
From: Naveed Khan
Date: Wed, 29 Jul 2026 17:48:35 +0530
Subject: [PATCH 5/6] split list elements on whitespace, quotes and the
delimiter only
Reset the StreamTokenizer syntax table in ArrayConverter.parseElements so
every character is part of an element except whitespace, the delimiter and
the quote characters. first_value,second_value and first/value,second/value
now both parse to two elements instead of four, and the default comment
char is gone as part of the reset. setAllowedChars no longer has any
effect and is deprecated. A plain split on the delimiter was ruled out
because ConvertUtilsTest pins whitespace separation and quote handling.
---
.../beanutils2/converters/ArrayConverter.java | 40 +++++++++----------
.../commons/beanutils2/bugs/Jira359Test.java | 8 ++--
.../converters/ArrayConverterTest.java | 36 ++++-------------
3 files changed, 30 insertions(+), 54 deletions(-)
diff --git a/src/main/java/org/apache/commons/beanutils2/converters/ArrayConverter.java b/src/main/java/org/apache/commons/beanutils2/converters/ArrayConverter.java
index e2c1c112b..39a133a05 100644
--- a/src/main/java/org/apache/commons/beanutils2/converters/ArrayConverter.java
+++ b/src/main/java/org/apache/commons/beanutils2/converters/ArrayConverter.java
@@ -64,11 +64,12 @@
*
*
*
- * Parsing Delimited Lists
This implementation can convert a delimited list in {@code String} format into an array of the appropriate type. By default,
- * it uses a comma as the delimiter but the following methods can be used to configure parsing:
+ * Parsing Delimited Lists
This implementation can convert a delimited list in {@code String} format into an array of the appropriate type. The
+ * String is split on the delimiter and on whitespace; every other character is kept as part of an element, and elements may be quoted with single or double
+ * quotes to protect embedded whitespace or delimiters. By default, it uses a comma as the delimiter but the following method can be used to configure
+ * parsing:
*
* - {@code setDelimiter(char)} - allows the character used as the delimiter to be configured [default is a comma].
- * - {@code setAllowedChars(char[])} - adds additional characters (to the default alphabetic/numeric) to those considered to be valid token characters.
*
*
* Multi Dimensional Arrays
It is possible to convert a {@code String} to multi-dimensional arrays by using {@link ArrayConverter} as the element
@@ -89,11 +90,8 @@
* // Construct a "Matrix" Converter which converts arrays of integer arrays using
* // the preceding ArrayConverter as the element Converter.
* // Uses a semicolon (i.e. ";") as the delimiter to separate the different sets of numbers.
- * // Also the delimiter used by the first ArrayConverter needs to be added to the
- * // "allowed characters" for this one.
* ArrayConverter matrixConverter = new ArrayConverter(int[][].class, arrayConverter);
* matrixConverter.setDelimiter(';');
- * matrixConverter.setAllowedChars(new char[] { ',' });
*
* // Do the Conversion
* String matrixString = "11,12,13 ; 21,22,23 ; 31,32,33 ; 41,42,43";
@@ -310,10 +308,10 @@ protected Class getDefaultType() {
* according to the following rules.
*
*
- * - The string is expected to be a comma-separated list of values.
+ * - The string is split on the delimiter [default is a comma] and on whitespace; every other character is kept as part of an element.
* - The string may optionally have matching '{' and '}' delimiters around the list.
- * - Whitespace before and after each element is stripped.
- * - Elements in the list may be delimited by single or double quotes. Within a quoted elements, the normal Java escape sequences are valid.
+ * - Elements in the list may be delimited by single or double quotes. A quoted element may contain whitespace and the delimiter, and within a quoted
+ * element the normal Java escape sequences are valid.
*
*
* @param value String value to be parsed
@@ -335,18 +333,18 @@ private List parseElements(String value) {
final String typeName = toString(String.class);
try {
- // Set up a StreamTokenizer on the characters in this String
+ // Set up a StreamTokenizer on the characters in this String. Every character is part of a token except whitespace, the quote characters and the
+ // delimiter, so elements are only split on those. The default syntax table would also split on any other non-alphanumeric character and treat
+ // '/' as a comment start, silently dropping the rest of the input.
final StreamTokenizer st = new StreamTokenizer(new StringReader(value));
- st.whitespaceChars(delimiter, delimiter); // Set the delimiters
- st.ordinaryChars('0', '9'); // Needed to turn off numeric flag
- st.wordChars('0', '9'); // Needed to make part of tokens
- st.ordinaryChar('/'); // Turn off the default comment character so it splits like any other separator
- for (final char allowedChar : allowedChars) {
- st.ordinaryChars(allowedChar, allowedChar);
- st.wordChars(allowedChar, allowedChar);
- }
-
- // Split comma-delimited tokens into a List
+ st.resetSyntax();
+ st.wordChars(0, 255); // Everything is part of a token...
+ st.whitespaceChars(0, ' '); // ...except whitespace...
+ st.quoteChar('"'); // ...quoted elements, which may contain whitespace and the delimiter...
+ st.quoteChar('\'');
+ st.whitespaceChars(delimiter, delimiter); // ...and the delimiter, which separates elements.
+
+ // Split the tokens into a List
List list = null;
while (true) {
final int ttype = st.nextToken();
@@ -383,7 +381,9 @@ private List parseElements(String value) {
* Sets the allowed characters to be used for parsing a delimited String.
*
* @param allowedChars Characters which are to be considered as part of the tokens when parsing a delimited String [default is '.' and '-']
+ * @deprecated No longer has any effect: every character apart from whitespace, the delimiter and the quote characters is kept as part of an element.
*/
+ @Deprecated
public void setAllowedChars(final char[] allowedChars) {
this.allowedChars = Objects.requireNonNull(allowedChars, "allowedChars").clone();
}
diff --git a/src/test/java/org/apache/commons/beanutils2/bugs/Jira359Test.java b/src/test/java/org/apache/commons/beanutils2/bugs/Jira359Test.java
index fc54c7657..da275b38f 100644
--- a/src/test/java/org/apache/commons/beanutils2/bugs/Jira359Test.java
+++ b/src/test/java/org/apache/commons/beanutils2/bugs/Jira359Test.java
@@ -105,11 +105,9 @@ void testBeanUtilsSetProperty_DefaultConvertStringToArray_WithColonValue() throw
final SimplePojoData simplePojo = new SimplePojoData();
BeanUtils.setProperty(simplePojo, "jcrMixinTypes", "mix:rereferencible,mix:simple");
showArray("Default WithColonValue", simplePojo.getJcrMixinTypes());
- assertEquals(4, simplePojo.getJcrMixinTypes().length, "array size");
- assertEquals("mix", simplePojo.getJcrMixinTypes()[0]);
- assertEquals("rereferencible", simplePojo.getJcrMixinTypes()[1]);
- assertEquals("mix", simplePojo.getJcrMixinTypes()[2]);
- assertEquals("simple", simplePojo.getJcrMixinTypes()[3]);
+ assertEquals(2, simplePojo.getJcrMixinTypes().length, "array size");
+ assertEquals("mix:rereferencible", simplePojo.getJcrMixinTypes()[0]);
+ assertEquals("mix:simple", simplePojo.getJcrMixinTypes()[1]);
}
/**
diff --git a/src/test/java/org/apache/commons/beanutils2/converters/ArrayConverterTest.java b/src/test/java/org/apache/commons/beanutils2/converters/ArrayConverterTest.java
index 8cd693f96..890e4e333 100644
--- a/src/test/java/org/apache/commons/beanutils2/converters/ArrayConverterTest.java
+++ b/src/test/java/org/apache/commons/beanutils2/converters/ArrayConverterTest.java
@@ -163,22 +163,14 @@ void testErrors() {
assertThrows(NullPointerException.class, () -> new ArrayConverter(int[].class, null));
}
+ /**
+ * A forward slash must be kept as part of an element instead of starting a comment and dropping the rest of the input.
+ */
@Test
void testForwardSlashSeparator() {
final String value = "first/value,second/value";
final ArrayConverter converter = new ArrayConverter<>(String[].class, new StringConverter());
- // test forward slash not allowed (the default)
- String[] result = converter.convert(String[].class, value);
- assertNotNull(result, "result.null");
- assertEquals(4, result.length, "result.length");
- assertEquals("first", result[0], "result[0]");
- assertEquals("value", result[1], "result[1]");
- assertEquals("second", result[2], "result[2]");
- assertEquals("value", result[3], "result[3]");
- // configure the converter to allow forward slash
- converter.setAllowedChars(new char[] { '.', '-', '/' });
- // test forward slash allowed
- result = converter.convert(String[].class, value);
+ final String[] result = converter.convert(String[].class, value);
assertNotNull(result, "result.null");
assertEquals(2, result.length, "result.length");
assertEquals("first/value", result[0], "result[0]");
@@ -249,11 +241,8 @@ void testTheMatrix() {
// Construct a "Matrix" Converter which converts arrays of integer arrays using
// the first (int[]) Converter as the element Converter.
// Uses a semicolon (i.e. ";") as the delimiter to separate the different sets of numbers.
- // Also the delimiter for the above array Converter needs to be added to this
- // array Converter's "allowed characters"
final ArrayConverter matrixConverter = new ArrayConverter(int[][].class, arrayConverter);
matrixConverter.setDelimiter(';');
- matrixConverter.setAllowedChars(new char[] { ',' });
// Do the Conversion
final Object result = matrixConverter.convert(int[][].class, matrixString);
// Check it actually worked OK
@@ -271,24 +260,13 @@ void testTheMatrix() {
}
/**
- * Test for BEANUTILS-302 throwing a NPE when underscore used.
+ * Test for BEANUTILS-302 throwing a NPE when underscore used. The underscore is kept as part of the element.
*/
@Test
void testUnderscore_BEANUTILS_302() {
final String value = "first_value,second_value";
- final ArrayConverter converter = new ArrayConverter(String[].class, new StringConverter());
- // test underscore not allowed (the default)
- String[] result = converter.convert(String[].class, value);
- assertNotNull(result, "result.null");
- assertEquals(4, result.length, "result.length");
- assertEquals("first", result[0], "result[0]");
- assertEquals("value", result[1], "result[1]");
- assertEquals("second", result[2], "result[2]");
- assertEquals("value", result[3], "result[3]");
- // configure the converter to allow underscore
- converter.setAllowedChars(new char[] { '.', '-', '_' });
- // test underscore allowed
- result = converter.convert(String[].class, value);
+ final ArrayConverter converter = new ArrayConverter<>(String[].class, new StringConverter());
+ final String[] result = converter.convert(String[].class, value);
assertNotNull(result, "result.null");
assertEquals(2, result.length, "result.length");
assertEquals("first_value", result[0], "result[0]");
From 8acb330d8a54d8e9f5bdb6c28fdbabb5c866a5eb Mon Sep 17 00:00:00 2001
From: Gary Gregory
Date: Wed, 29 Jul 2026 09:41:34 -0400
Subject: [PATCH 6/6] Revise deprecation message in ArrayConverter
Updated deprecation notice for setAllowedChars method.
---
.../apache/commons/beanutils2/converters/ArrayConverter.java | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/src/main/java/org/apache/commons/beanutils2/converters/ArrayConverter.java b/src/main/java/org/apache/commons/beanutils2/converters/ArrayConverter.java
index 39a133a05..5f8faae34 100644
--- a/src/main/java/org/apache/commons/beanutils2/converters/ArrayConverter.java
+++ b/src/main/java/org/apache/commons/beanutils2/converters/ArrayConverter.java
@@ -381,7 +381,8 @@ private List parseElements(String value) {
* Sets the allowed characters to be used for parsing a delimited String.
*
* @param allowedChars Characters which are to be considered as part of the tokens when parsing a delimited String [default is '.' and '-']
- * @deprecated No longer has any effect: every character apart from whitespace, the delimiter and the quote characters is kept as part of an element.
+ * @deprecated Since 1.12.0: No longer has any effect: every character apart from whitespace, the delimiter and the quote characters is kept
+ * as part of an element.
*/
@Deprecated
public void setAllowedChars(final char[] allowedChars) {