This is an automated email from the ASF dual-hosted git repository. rmaucher pushed a commit to branch main in repository https://gitbox.apache.org/repos/asf/tomcat.git
commit 281d550adf6aa22e8858f07357cd8453ce61e37a Author: opencode <[email protected]> AuthorDate: Sun Oct 18 17:05:30 2026 +0200 Correct the method call check in AstValue.getValueReference The value reference of an expression is null unless the expression is a reference to a property of a base object. To tell a method call from a property reference, getValueReference checked whether the third child of the value node was the parameter list. The parameter list is the last child of a value node, which is only the third child when the expression is a single method call. Two shapes were therefore misclassified. A property of the result of a method call, such as ${bean.select('x').name}, reported no value reference although it is a reference to the name property of the object the method call returns. A method call on the result of a property, such as ${bean.target.select('x')}, reported a value reference for the property and the name of the method, and even evaluated the property along the way, although a method call must not produce a value reference at all. Use the class's own check for the presence of a parameter list, the same one the evaluation of the node uses, in place of the positional guess. Method calls are now recognised before the base is resolved, so they return null without evaluating anything. Adds tests for a method call, for a property of the result of a method call and for a method call on the result of a property, along with a test bean that provides such a method. Two of the three report the wrong result against the previous implementation. --- java/org/apache/el/parser/AstValue.java | 2 +- test/org/apache/el/TestValueExpressionImpl.java | 53 +++++++++++++++++++++++++ test/org/apache/el/TesterBeanM.java | 38 ++++++++++++++++++ 3 files changed, 92 insertions(+), 1 deletion(-) diff --git a/java/org/apache/el/parser/AstValue.java b/java/org/apache/el/parser/AstValue.java index 389a81636c..aa93ab81cd 100644 --- a/java/org/apache/el/parser/AstValue.java +++ b/java/org/apache/el/parser/AstValue.java @@ -434,7 +434,7 @@ public final class AstValue extends SimpleNode { @Override public ValueReference getValueReference(EvaluationContext ctx) { // Check this is a reference to a base and a property - if (this.children.length > 2 && this.jjtGetChild(2) instanceof AstMethodParameters) { + if (isParametersProvided()) { // This is a method call return null; } diff --git a/test/org/apache/el/TestValueExpressionImpl.java b/test/org/apache/el/TestValueExpressionImpl.java index fd3a789564..786acff235 100644 --- a/test/org/apache/el/TestValueExpressionImpl.java +++ b/test/org/apache/el/TestValueExpressionImpl.java @@ -86,6 +86,59 @@ public class TestValueExpressionImpl extends ELBaseTest { Assert.assertEquals("name", vr.getProperty()); } + @Test + public void testGetValueReferenceMethodCall() { + ExpressionFactory factory = ExpressionFactory.newInstance(); + ELContext context = new ELContextImpl(); + + TesterBeanM beanM = new TesterBeanM(); + ValueExpression var = factory.createValueExpression(beanM, TesterBeanM.class); + context.getVariableMapper().setVariable("beanM", var); + + ValueExpression ve = factory.createValueExpression(context, "${beanM.select('Tomcat')}", String.class); + + // A method call is not a reference to a base and a property + ValueReference vr = ve.getValueReference(context); + Assert.assertNull(vr); + } + + @Test + public void testGetValueReferenceMethodCallResult() { + ExpressionFactory factory = ExpressionFactory.newInstance(); + ELContext context = new ELContextImpl(); + + TesterBeanM beanM = new TesterBeanM(); + ValueExpression var = factory.createValueExpression(beanM, TesterBeanM.class); + context.getVariableMapper().setVariable("beanM", var); + + ValueExpression ve = factory.createValueExpression(context, "${beanM.select('Tomcat').name}", String.class); + + // The result of the method call is the base of the property + // reference, so this is a reference to a base and a property + ValueReference vr = ve.getValueReference(context); + Assert.assertNotNull(vr); + + Assert.assertEquals(beanM.getTarget(), vr.getBase()); + Assert.assertEquals("name", vr.getProperty()); + } + + @Test + public void testGetValueReferencePropertyThenMethodCall() { + ExpressionFactory factory = ExpressionFactory.newInstance(); + ELContext context = new ELContextImpl(); + + TesterBeanM beanM = new TesterBeanM(); + ValueExpression var = factory.createValueExpression(beanM, TesterBeanM.class); + context.getVariableMapper().setVariable("beanM", var); + + ValueExpression ve = factory.createValueExpression(context, "${beanM.target.select('Tomcat')}", String.class); + + // A method call is not a reference to a base and a property, even + // when the base of the method call is itself a property + ValueReference vr = ve.getValueReference(context); + Assert.assertNull(vr); + } + @Test public void testBug49345() { ExpressionFactory factory = ExpressionFactory.newInstance(); diff --git a/test/org/apache/el/TesterBeanM.java b/test/org/apache/el/TesterBeanM.java new file mode 100644 index 0000000000..285fbe18ff --- /dev/null +++ b/test/org/apache/el/TesterBeanM.java @@ -0,0 +1,38 @@ +/* + * 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 + * + * http://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.el; + +/* + * Provides a method that takes a parameter and returns a bean, for tests of + * the value reference of expressions that combine method calls and property + * references. + */ +public class TesterBeanM { + + private final TesterBeanB target = new TesterBeanB(); + + + public TesterBeanB getTarget() { + return target; + } + + + public TesterBeanB select(String name) { + target.setName(name); + return target; + } +} --------------------------------------------------------------------- To unsubscribe, e-mail: [email protected] For additional commands, e-mail: [email protected]
