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

rmaucher pushed a commit to branch 11.0.x
in repository https://gitbox.apache.org/repos/asf/tomcat.git

commit 995bb35a82fc0d6b9f3f79cb00e32a14702c41cf
Author: opencode <[email protected]>
AuthorDate: Tue Oct 20 11:46:14 2026 +0200

    Report a bean property value which cannot be converted as a NamingException
    
    BeanFactory converts the value of each configured address of a resource
    reference to the type of the bean property which it names, using the
    conversion methods of the numeric types and, for a character property,
    the first character of the value. A value which does not match the type,
    such as a word for a property which is an integer, made one of those
    methods throw a NumberFormatException and an empty value for a character
    property made the reading of the first character throw a
    StringIndexOutOfBoundsException. As neither is one of the exceptions
    which the factory catches, it escaped the factory despite the
    NamingException which its contract promises for an error while the
    instance is created. The failure which reached the operator was then the
    unchecked exception alone, which names neither the property nor its
    value and so gave no clue which attribute of the resource was
    misconfigured.
    
    Such a value now leads to the NamingException which the contract
    promises, naming the value, the property and the type, with the
    exception of the conversion as its cause. A value which can be converted
    is converted as before.
    
    Add tests which check both a value which is not a number for a property
    which is an integer and an empty value for a character property.
---
 java/org/apache/naming/factory/BeanFactory.java    | 70 +++++++++++++---------
 .../apache/naming/factory/LocalStrings.properties  |  1 +
 .../org/apache/naming/factory/TestBeanFactory.java | 51 ++++++++++++++++
 test/org/apache/naming/factory/TesterBean.java     | 20 +++++++
 4 files changed, 114 insertions(+), 28 deletions(-)

diff --git a/java/org/apache/naming/factory/BeanFactory.java 
b/java/org/apache/naming/factory/BeanFactory.java
index 3b776be98d..54e34f5b3c 100644
--- a/java/org/apache/naming/factory/BeanFactory.java
+++ b/java/org/apache/naming/factory/BeanFactory.java
@@ -139,38 +139,52 @@ public class BeanFactory implements ObjectFactory {
                             Class<?> propType = pda[i].getPropertyType();
                             Method setProp = pda[i].getWriteMethod();
 
-                            if (propType.equals(String.class)) {
-                                valueArray[0] = value;
-                            } else if (propType.equals(Character.class) || 
propType.equals(char.class)) {
-                                valueArray[0] = 
Character.valueOf(value.charAt(0));
-                            } else if (propType.equals(Byte.class) || 
propType.equals(byte.class)) {
-                                valueArray[0] = Byte.valueOf(value);
-                            } else if (propType.equals(Short.class) || 
propType.equals(short.class)) {
-                                valueArray[0] = Short.valueOf(value);
-                            } else if (propType.equals(Integer.class) || 
propType.equals(int.class)) {
-                                valueArray[0] = Integer.valueOf(value);
-                            } else if (propType.equals(Long.class) || 
propType.equals(long.class)) {
-                                valueArray[0] = Long.valueOf(value);
-                            } else if (propType.equals(Float.class) || 
propType.equals(float.class)) {
-                                valueArray[0] = Float.valueOf(value);
-                            } else if (propType.equals(Double.class) || 
propType.equals(double.class)) {
-                                valueArray[0] = Double.valueOf(value);
-                            } else if (propType.equals(Boolean.class) || 
propType.equals(boolean.class)) {
-                                valueArray[0] = Boolean.valueOf(value);
-                            } else if (setProp != null) {
-                                // This is a Tomcat specific extension and is 
not part of the
-                                // Java Bean specification.
-                                String setterName = setProp.getName();
-                                try {
-                                    setProp = 
bean.getClass().getMethod(setterName, String.class);
+                            // The conversion methods of the numeric types and
+                            // the reading of the first character report an
+                            // invalid value of a configured property with an
+                            // unchecked exception, which is replaced here by a
+                            // NamingException which names the property, its
+                            // value and its type.
+                            try {
+                                if (propType.equals(String.class)) {
                                     valueArray[0] = value;
-                                } catch (NoSuchMethodException nsme) {
+                                } else if (propType.equals(Character.class) || 
propType.equals(char.class)) {
+                                    valueArray[0] = 
Character.valueOf(value.charAt(0));
+                                } else if (propType.equals(Byte.class) || 
propType.equals(byte.class)) {
+                                    valueArray[0] = Byte.valueOf(value);
+                                } else if (propType.equals(Short.class) || 
propType.equals(short.class)) {
+                                    valueArray[0] = Short.valueOf(value);
+                                } else if (propType.equals(Integer.class) || 
propType.equals(int.class)) {
+                                    valueArray[0] = Integer.valueOf(value);
+                                } else if (propType.equals(Long.class) || 
propType.equals(long.class)) {
+                                    valueArray[0] = Long.valueOf(value);
+                                } else if (propType.equals(Float.class) || 
propType.equals(float.class)) {
+                                    valueArray[0] = Float.valueOf(value);
+                                } else if (propType.equals(Double.class) || 
propType.equals(double.class)) {
+                                    valueArray[0] = Double.valueOf(value);
+                                } else if (propType.equals(Boolean.class) || 
propType.equals(boolean.class)) {
+                                    valueArray[0] = Boolean.valueOf(value);
+                                } else if (setProp != null) {
+                                    // This is a Tomcat specific extension and 
is not part of the
+                                    // Java Bean specification.
+                                    String setterName = setProp.getName();
+                                    try {
+                                        setProp = 
bean.getClass().getMethod(setterName, String.class);
+                                        valueArray[0] = value;
+                                    } catch (NoSuchMethodException nsme) {
+                                        throw new NamingException(
+                                                
sm.getString("beanFactory.noStringConversion", propName,
+                                                        propType.getName()));
+                                    }
+                                } else {
                                     throw new 
NamingException(sm.getString("beanFactory.noStringConversion", propName,
                                             propType.getName()));
                                 }
-                            } else {
-                                throw new NamingException(
-                                        
sm.getString("beanFactory.noStringConversion", propName, propType.getName()));
+                            } catch (NumberFormatException | 
StringIndexOutOfBoundsException ex) {
+                                NamingException ne = new 
NamingException(sm.getString("beanFactory.invalidValue",
+                                        value, propName, propType.getName()));
+                                ne.initCause(ex);
+                                throw ne;
                             }
 
                             if (setProp != null) {
diff --git a/java/org/apache/naming/factory/LocalStrings.properties 
b/java/org/apache/naming/factory/LocalStrings.properties
index 4a54e94849..04843fa857 100644
--- a/java/org/apache/naming/factory/LocalStrings.properties
+++ b/java/org/apache/naming/factory/LocalStrings.properties
@@ -17,6 +17,7 @@
 # To edit translations see: 
https://tomcat.apache.org/getinvolved.html#Translations
 
 beanFactory.classNotFound=Class not found: [{0}]
+beanFactory.invalidValue=The value [{0}] of the property [{1}] cannot be 
converted to the type [{2}]
 beanFactory.noForceString=The forceString option has been removed as a 
security hardening measure. Instead, if the setter method doesn't use String, a 
primitive or a primitive wrapper, the factory will look for a method with the 
same name as the setter that accepts a String and use that if found.
 beanFactory.noSetMethod=No set method found for property [{0}]
 beanFactory.noStringConversion=String conversion for property [{0}] of type 
[{1}] not available
diff --git a/test/org/apache/naming/factory/TestBeanFactory.java 
b/test/org/apache/naming/factory/TestBeanFactory.java
index 79912c7d0c..ceb2211a7b 100644
--- a/test/org/apache/naming/factory/TestBeanFactory.java
+++ b/test/org/apache/naming/factory/TestBeanFactory.java
@@ -16,6 +16,7 @@
  */
 package org.apache.naming.factory;
 
+import javax.naming.NamingException;
 import javax.naming.StringRefAddr;
 
 import org.junit.Assert;
@@ -91,4 +92,54 @@ public class TestBeanFactory {
         Assert.assertNotNull(result.getServer());
         Assert.assertEquals(IP_ADDRESS, result.getServer().getHostAddress());
     }
+
+
+    /*
+     * A value which does not match the type of the property is a configuration
+     * error which has to be reported as a NamingException with the property as
+     * context, not as the unchecked exception of the conversion.
+     */
+    @Test
+    public void testValueNotMatchingThePropertyTypeIsReported() throws 
Exception {
+
+        ResourceRef resourceRef = new ResourceRef(TesterBean.class.getName(), 
null, null, null, false);
+        resourceRef.add(new StringRefAddr("limit", "not-a-number"));
+
+        BeanFactory factory = new BeanFactory();
+
+        try {
+            Object obj = factory.getObjectInstance(resourceRef, null, null, 
null);
+            Assert.fail("The invalid value was accepted: " + obj);
+        } catch (NamingException e) {
+            Assert.assertTrue("The property is not named: " + e.getMessage(), 
e.getMessage().contains("limit"));
+            Assert.assertTrue("The value is not named: " + e.getMessage(), 
e.getMessage().contains("not-a-number"));
+            Assert.assertTrue("The reason for the failure is not reported",
+                    e.getCause() instanceof NumberFormatException);
+        }
+    }
+
+
+    /*
+     * The value of a character property is read from the first character of
+     * the configured value, so an empty value has to be reported in the same
+     * way as a value which cannot be converted.
+     */
+    @Test
+    public void testEmptyValueForCharacterPropertyIsReported() throws 
Exception {
+
+        ResourceRef resourceRef = new ResourceRef(TesterBean.class.getName(), 
null, null, null, false);
+        resourceRef.add(new StringRefAddr("letter", ""));
+
+        BeanFactory factory = new BeanFactory();
+
+        try {
+            Object obj = factory.getObjectInstance(resourceRef, null, null, 
null);
+            Assert.fail("The invalid value was accepted: " + obj);
+        } catch (NamingException e) {
+            Assert.assertTrue("The property is not named: " + e.getMessage(), 
e.getMessage().contains("letter"));
+            Assert.assertTrue("The type is not named: " + e.getMessage(), 
e.getMessage().contains("char"));
+            Assert.assertTrue("The reason for the failure is not reported",
+                    e.getCause() instanceof StringIndexOutOfBoundsException);
+        }
+    }
 }
diff --git a/test/org/apache/naming/factory/TesterBean.java 
b/test/org/apache/naming/factory/TesterBean.java
index d2beef275c..654e9fef28 100644
--- a/test/org/apache/naming/factory/TesterBean.java
+++ b/test/org/apache/naming/factory/TesterBean.java
@@ -23,6 +23,10 @@ public class TesterBean {
 
     private InetAddress server;
 
+    private int limit;
+
+    private char letter;
+
     public InetAddress getServer() {
         return server;
     }
@@ -38,4 +42,20 @@ public class TesterBean {
             throw new IllegalArgumentException(e);
         }
     }
+
+    public int getLimit() {
+        return limit;
+    }
+
+    public void setLimit(int limit) {
+        this.limit = limit;
+    }
+
+    public char getLetter() {
+        return letter;
+    }
+
+    public void setLetter(char letter) {
+        this.letter = letter;
+    }
 }


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to