This is an automated email from the ASF dual-hosted git repository.

garydgregory pushed a commit to branch 1.X
in repository https://gitbox.apache.org/repos/asf/commons-beanutils.git


The following commit(s) were added to refs/heads/1.X by this push:
     new 28125b04 Case-fold column and bean property names with Locale.ROOT 
(1.X) (#417)
28125b04 is described below

commit 28125b04836432d342fd61977115c9c1dfca0af2
Author: Naveed Khan <[email protected]>
AuthorDate: Mon Jul 13 22:32:08 2026 +0000

    Case-fold column and bean property names with Locale.ROOT (1.X) (#417)
    
    port of #415: default-locale toLowerCase/toUpperCase mangle identifiers 
under a Turkish locale (column ID becomes a property with a dotless i, and 
getImages is rebuilt with a dotted I); fold with Locale.ROOT in JDBCDynaClass 
and DefaultBeanIntrospector. the regression test uses @DefaultLocale from 
junit-pioneer per review feedback on #415, added as a test dependency (1.9.1, 
the last Java 8 compatible line).
---
 pom.xml                                            |  7 +++
 .../commons/beanutils/DefaultBeanIntrospector.java |  3 +-
 .../apache/commons/beanutils/JDBCDynaClass.java    |  3 +-
 .../commons/beanutils/JdbcDynaClassLocaleTest.java | 73 ++++++++++++++++++++++
 4 files changed, 84 insertions(+), 2 deletions(-)

diff --git a/pom.xml b/pom.xml
index b998c0c5..905fc341 100644
--- a/pom.xml
+++ b/pom.xml
@@ -113,6 +113,13 @@
       <artifactId>junit-jupiter</artifactId>
       <scope>test</scope>
     </dependency>
+    <dependency>
+      <groupId>org.junit-pioneer</groupId>
+      <artifactId>junit-pioneer</artifactId>
+      <!-- 2.x requires Java 11 -->
+      <version>1.9.1</version>
+      <scope>test</scope>
+    </dependency>
   </dependencies>
   <build>
       <defaultGoal>clean apache-rat:check verify japicmp:cmp javadoc:javadoc 
checkstyle:check</defaultGoal>
diff --git 
a/src/main/java/org/apache/commons/beanutils/DefaultBeanIntrospector.java 
b/src/main/java/org/apache/commons/beanutils/DefaultBeanIntrospector.java
index 9ed22023..4ab5df6d 100644
--- a/src/main/java/org/apache/commons/beanutils/DefaultBeanIntrospector.java
+++ b/src/main/java/org/apache/commons/beanutils/DefaultBeanIntrospector.java
@@ -23,6 +23,7 @@ import java.beans.Introspector;
 import java.beans.PropertyDescriptor;
 import java.lang.reflect.Method;
 import java.util.List;
+import java.util.Locale;
 
 import org.apache.commons.logging.Log;
 import org.apache.commons.logging.LogFactory;
@@ -95,7 +96,7 @@ public class DefaultBeanIntrospector implements 
BeanIntrospector {
             if (pd instanceof IndexedPropertyDescriptor) {
                 final IndexedPropertyDescriptor descriptor = 
(IndexedPropertyDescriptor) pd;
                 final String propName = descriptor.getName().substring(0, 1)
-                        .toUpperCase()
+                        .toUpperCase(Locale.ROOT)
                         + descriptor.getName().substring(1);
 
                 if (descriptor.getReadMethod() == null) {
diff --git a/src/main/java/org/apache/commons/beanutils/JDBCDynaClass.java 
b/src/main/java/org/apache/commons/beanutils/JDBCDynaClass.java
index e89acce7..c993b3fb 100644
--- a/src/main/java/org/apache/commons/beanutils/JDBCDynaClass.java
+++ b/src/main/java/org/apache/commons/beanutils/JDBCDynaClass.java
@@ -26,6 +26,7 @@ import java.sql.Time;
 import java.sql.Timestamp;
 import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.Locale;
 import java.util.Map;
 
 /**
@@ -89,7 +90,7 @@ abstract class JDBCDynaClass implements DynaClass, 
Serializable {
         if (columnName == null || columnName.trim().length() == 0) {
             columnName = metadata.getColumnName(i);
         }
-        final String name = lowerCase ? columnName.toLowerCase() : columnName;
+        final String name = lowerCase ? columnName.toLowerCase(Locale.ROOT) : 
columnName;
         if (!name.equals(columnName)) {
             if (columnNameXref == null) {
                 columnNameXref = new HashMap<>();
diff --git 
a/src/test/java/org/apache/commons/beanutils/JdbcDynaClassLocaleTest.java 
b/src/test/java/org/apache/commons/beanutils/JdbcDynaClassLocaleTest.java
new file mode 100644
index 00000000..1c40ac9f
--- /dev/null
+++ b/src/test/java/org/apache/commons/beanutils/JdbcDynaClassLocaleTest.java
@@ -0,0 +1,73 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.commons.beanutils;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+
+import java.lang.reflect.InvocationHandler;
+import java.lang.reflect.Proxy;
+import java.sql.ResultSet;
+import java.sql.ResultSetMetaData;
+import java.sql.Types;
+
+import org.junit.jupiter.api.Test;
+import org.junitpioneer.jupiter.DefaultLocale;
+
+/**
+ * Tests that column names are folded to lower case independently of the 
default locale.
+ */
+class JdbcDynaClassLocaleTest {
+
+    private static ResultSet singleColumnResultSet(final String columnName) {
+        final InvocationHandler metaData = (proxy, method, args) -> {
+            switch (method.getName()) {
+            case "getColumnCount":
+                return Integer.valueOf(1);
+            case "getColumnLabel":
+            case "getColumnName":
+                return columnName;
+            case "getColumnType":
+                return Integer.valueOf(Types.VARCHAR);
+            case "getColumnClassName":
+                return String.class.getName();
+            default:
+                throw new UnsupportedOperationException(method.getName());
+            }
+        };
+        final ResultSetMetaData metaDataProxy = (ResultSetMetaData) 
Proxy.newProxyInstance(ResultSetMetaData.class.getClassLoader(),
+                new Class[] { ResultSetMetaData.class }, metaData);
+        final InvocationHandler resultSet = (proxy, method, args) -> {
+            if ("getMetaData".equals(method.getName())) {
+                return metaDataProxy;
+            }
+            throw new UnsupportedOperationException(method.getName());
+        };
+        return (ResultSet) 
Proxy.newProxyInstance(ResultSet.class.getClassLoader(), new Class[] { 
ResultSet.class }, resultSet);
+    }
+
+    @Test
+    @DefaultLocale(language = "tr", country = "TR")
+    void testColumnNameLowerCasedIndependentOfLocale() throws Exception {
+        // Under the Turkish locale "ID".toLowerCase() is "ıd" (dotless i), 
not "id".
+        final ResultSetDynaClass dynaClass = new 
ResultSetDynaClass(singleColumnResultSet("ID"));
+        final DynaProperty property = dynaClass.getDynaProperty("id");
+        assertNotNull(property, "column 'ID' must map to property 'id'");
+        assertEquals("id", property.getName());
+    }
+}

Reply via email to