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 dc728f082c7f1897297307addec5165c88b240e9 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 7f0cc65111..27c0e653f1 100644 --- a/java/org/apache/el/parser/AstValue.java +++ b/java/org/apache/el/parser/AstValue.java @@ -427,7 +427,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 465ee1480c..9f73939fef 100644 --- a/test/org/apache/el/TestValueExpressionImpl.java +++ b/test/org/apache/el/TestValueExpressionImpl.java @@ -84,6 +84,59 @@ public class TestValueExpressionImpl { 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]
