Bug 61854 - Function not found when using maps or sets in EL expressions
Summary: Function not found when using maps or sets in EL expressions
Alias: None
Product: Tomcat 9
Classification: Unclassified
Component: Jasper (show other bugs)
Version: 9.0.2
Hardware: PC Linux
: P2 normal (vote)
Target Milestone: -----
Assignee: Tomcat Developers Mailing List
Depends on:
Reported: 2017-12-04 09:33 UTC by Ricardo Martin Camarero
Modified: 2017-12-06 14:53 UTC (History)
0 users

JSP example for trhe bug (361.09 KB, application/zip)
2017-12-04 09:33 UTC, Ricardo Martin Camarero

Note You need to log in before you can comment on or make changes to this bug.
Description Ricardo Martin Camarero 2017-12-04 09:33:25 UTC
Created attachment 35582 [details]
JSP example for trhe bug

The EL specification 3.0 defines the use of maps and sets like this:

sets: {1, 2, 3}
maps: {"one":1, "two":2, "three":3}

See chapter 2.2 Construction of Collection Objects in the specification http://download.oracle.com/otndocs/jcp/el-3_0-fr-eval-spec/index.html

So in EL 3.0 a expression like this is is valid:

${ map = {'1':'2', 'a':'b'}; fn:length(map['a']) }

It should return 1. In all tomcat versions this throws:

org.apache.jasper.JasperException: org.apache.jasper.JasperException: javax.el.ELException: Function [fn:length] not found

The main reason seems to be that the ELParser that register the functions does not take into account that a closing bracket is now possible before closing the real EL expression. So it is closing the expression before and the function is not registered (and it's not found later on). The following change makes it work:

--- java/org/apache/jasper/compiler/ELParser.java	(revision 1817073)
+++ java/org/apache/jasper/compiler/ELParser.java	(working copy)
@@ -106,11 +106,17 @@
         ELexpr = new ELNode.Nodes();
         curToken = null;
         prevToken = null;
+        int openBracket = 0;
         while (hasNext()) {
             curToken = nextToken();
             if (curToken instanceof Char) {
                 if (curToken.toChar() == '}') {
-                    break;
+                    openBracket--;
+                    if (openBracket < 0) {
+                        break;
+                    }
+                } else if (curToken.toChar() == '{') {
+                    openBracket++;
             } else {

The modification just counts the opening brackets and the EL expression is only considered as complete when the brackets are all closed.
Comment 1 Mark Thomas 2017-12-06 14:53:27 UTC
Thanks for the report and the test webapp. I converted it to a Tomcat test and added it to the test suite.

Fixed in:
- trunk for 9.0.3 onwards
- 8.5.x for 8.5.25 onwards
- 8.0.x for 8.0.49 onwards