You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tomcat.apache.org by re...@apache.org on 2026/10/20 21:17:13 UTC
(tomcat) 12/21: Report a bean property value which cannot be converted as a NamingException
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 <re...@apache.org>
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: dev-unsubscribe@tomcat.apache.org
For additional commands, e-mail: dev-help@tomcat.apache.org