This is an automated email from the ASF dual-hosted git repository. rmaucher pushed a commit to branch 9.0.x in repository https://gitbox.apache.org/repos/asf/tomcat.git
commit cd54f9606de8548503fa30db53579507d4fb86d9 Author: opencode <[email protected]> AuthorDate: Mon Oct 19 10:33:12 2026 +0200 Report bean getter and setter exceptions in GraalVM mode GraalBeanELResolver caught exceptions raised while invoking a bean getter or setter, passed them through ExceptionUtils.handleThrowable() which only rethrows VirtualMachineError, and then returned as if the property had been resolved successfully. A throwing getter therefore yielded a null value and a throwing setter a silently dropped write. The ELResolver contract, and the standard BeanELResolver used outside GraalVM native image mode, wrap such failures in an ELException. Rethrow the unwrapped cause as an ELException after handleThrowable(), mirroring BeanELResolver so a native image build reports the same EL errors as a standard JVM. Test with bean properties whose accessor and mutator throw. Found by code review. --- java/org/apache/jasper/el/JasperELResolver.java | 12 +++++--- .../org/apache/jasper/el/TestJasperELResolver.java | 33 ++++++++++++++++++++++ 2 files changed, 41 insertions(+), 4 deletions(-) diff --git a/java/org/apache/jasper/el/JasperELResolver.java b/java/org/apache/jasper/el/JasperELResolver.java index ac003b893c..31de390053 100644 --- a/java/org/apache/jasper/el/JasperELResolver.java +++ b/java/org/apache/jasper/el/JasperELResolver.java @@ -212,8 +212,7 @@ public class JasperELResolver extends CompositeELResolver { method.setAccessible(true); value = method.invoke(base, (Object[]) null); } catch (Exception e) { - Throwable thr = ExceptionUtils.unwrapInvocationTargetException(e); - ExceptionUtils.handleThrowable(thr); + throw toELException(e); } } return value; @@ -235,8 +234,7 @@ public class JasperELResolver extends CompositeELResolver { method.setAccessible(true); method.invoke(base, value); } catch (Exception e) { - Throwable thr = ExceptionUtils.unwrapInvocationTargetException(e); - ExceptionUtils.handleThrowable(thr); + throw toELException(e); } } } @@ -281,6 +279,12 @@ public class JasperELResolver extends CompositeELResolver { return null; } + private static ELException toELException(Exception e) { + Throwable thr = ExceptionUtils.unwrapInvocationTargetException(e); + ExceptionUtils.handleThrowable(thr); + return new ELException(thr); + } + private static String capitalize(String name) { if (name == null || name.isEmpty()) { return name; diff --git a/test/org/apache/jasper/el/TestJasperELResolver.java b/test/org/apache/jasper/el/TestJasperELResolver.java index 14c6c37edd..ba3086b180 100644 --- a/test/org/apache/jasper/el/TestJasperELResolver.java +++ b/test/org/apache/jasper/el/TestJasperELResolver.java @@ -22,6 +22,7 @@ import java.util.List; import java.util.concurrent.atomic.AtomicInteger; import javax.el.ELContext; +import javax.el.ELException; import javax.el.ELResolver; import javax.servlet.jsp.el.ImplicitObjectELResolver; @@ -109,6 +110,32 @@ public class TestJasperELResolver { resolver.setValue(context, bean, "foo", Integer.valueOf(7)); Assert.assertFalse("A mismatched value must leave the property unresolved", context.isPropertyResolved()); + + // An exception thrown by a getter must be reported rather than + // swallowed. Before the fix it produced a silently resolved null. + context.setPropertyResolved(false); + try { + resolver.getValue(context, bean, "failing"); + Assert.fail("A getter exception must be reported"); + } catch (ELException e) { + Assert.assertTrue("The reported cause must be the thrown exception", + e.getCause() instanceof IllegalStateException); + Assert.assertEquals("getter failed", e.getCause().getMessage()); + Assert.assertTrue("A found property should be marked resolved", context.isPropertyResolved()); + } + + // An exception thrown by a setter must be reported rather than + // swallowed. Before the fix the failed write went unnoticed. + context.setPropertyResolved(false); + try { + resolver.setValue(context, bean, "failing", "some value"); + Assert.fail("A setter exception must be reported"); + } catch (ELException e) { + Assert.assertTrue("The reported cause must be the thrown exception", + e.getCause() instanceof IllegalStateException); + Assert.assertEquals("setter failed", e.getCause().getMessage()); + Assert.assertTrue("A found property should be marked resolved", context.isPropertyResolved()); + } } public static class TestBean { @@ -138,5 +165,11 @@ public class TestJasperELResolver { public Object getLastBla() { return bla; } + public String getFailing() { + throw new IllegalStateException("getter failed"); + } + public void setFailing(@SuppressWarnings("unused") String value) { + throw new IllegalStateException("setter failed"); + } } } --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
