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 457a4ee96e40e207257d0a6799deb937091d52ab 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 99f3caa853..b7f0d70888 100644 --- a/java/org/apache/jasper/el/JasperELResolver.java +++ b/java/org/apache/jasper/el/JasperELResolver.java @@ -218,8 +218,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; @@ -241,8 +240,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); } } } @@ -287,6 +285,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 d98699abf2..75132bbc9b 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 jakarta.el.ELContext; +import jakarta.el.ELException; import jakarta.el.ELResolver; import jakarta.servlet.jsp.el.ImplicitObjectELResolver; @@ -111,6 +112,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 { @@ -140,5 +167,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]
