Being convinced now that this is a Tomcat bug in violation of the spec--and not something I am doing wrong--I'm going to go ahead and file a bug now.
N On Nov 17, 2013, at 9:32 AM, Nick Williams wrote: > > On Nov 17, 2013, at 6:00 AM, Konstantin Kolinko wrote: > >> 2013/11/17 Nick Williams <nicho...@nicholaswilliams.net>: >>> I have an EL 3.0 edge case that I need help understanding. Am I doing >>> something wrong (I don't think so) or is the Tomcat 8.0 implementation >>> missing something? >>> >>> Consider the following EL expression: >>> >>> ${users.stream() >>> .filter(u -> fn:contains(u.username, '1')) >>> .sorted((u1, u2) -> u1.lastName.compareTo(u2.lastName) == 0 ? >>> u1.firstName.compareTo(u2.firstName) : u1.lastName.compareTo(u2.lastName)) >>> .toList()} >>> >>> This works as expected. However, it results in potentially evaluating >>> u1.lastName.compareTo(u2.lastName) twice. My understanding is that the >>> right-hand side of a lambda expression can be any valid EL expression, so I >>> believe this should also work: >>> >>> ${users.stream() >>> .filter(u -> fn:contains(u.username, '1')) >>> .sorted((u1, u2) -> x = u1.lastName.compareTo(u2.lastName); x >>> == 0 ? u1.firstName.compareTo(u2.firstName) : x) >>> .toList()} >>> >>> However, this doesn't evaluate. I get the following error instead: >>> >>> org.apache.el.parser.ParseException: Encountered " "=" "= "" at line 3, >>> column 38. >>> Was expecting one of: >>> "." ... >>> ")" ... >>> etc ... >>> >> >> What if you add "(" ")" ? >> What operator has higher priority, "->" or ";" ? > > "->" has higher priority than both "=" and ";", according to the spec. In > this particular case, I'm not sure whether that means parenthesis are > absolutely required or not. However, I can confirm that adding parenthesis > here solves this problem, so perhaps that's what I was doing wrong for this > error. This expression now works: > > ${users.stream() > .filter(u -> fn:contains(u.username, '1')) > .sorted((u1, u2) -> (x = u1.lastName.compareTo(u2.lastName); x > == 0 ? u1.firstName.compareTo(u2.firstName) : x)) > .toList()} > >>> Next I tried to reduce the properties present in each user using the stream >>> "map" method. Once again, with the understanding that the right-hand side >>> of a lambda expression can be any valid EL expression, I use an EL Map >>> literal to construct a reduced set of properties: >>> >>> ${users.stream() >>> .filter(u -> fn:contains(u.username, '1')) >>> .map(u -> {'username':u.username, 'first':u.firstName, >>> 'last':u.lastName}) >>> .sorted((u1, u2) -> u1.lastName.compareTo(u2.lastName) == 0 ? >>> u1.firstName.compareTo(u2.firstName) : u1.lastName.compareTo(u2.lastName)) >>> .toList()} >>> >>> However, that doesn't work and I get this error: >>> >>> org.apache.el.parser.ParseException: Encountered "<EOF>" at line 3, column >>> 88. >>> Was expecting one of: >>> "." ... >>> ")" ... >>> etc ... >>> >> >> I do not understand the above. Can you provide a simple test case? >> Which one of the expressions does not work? Can you remove the others? > > So, as mentioned above, the following expression works: > > ${users.stream() > .filter(u -> fn:contains(u.username, '1')) > .sorted((u1, u2) -> (x = u1.lastName.compareTo(u2.lastName); x > == 0 ? u1.firstName.compareTo(u2.firstName) : x)) > .toList()} > > If I now add the "map" operation to it, I get the EOF error. Nothing else > about the expression changed: > > ${users.stream() > .filter(u -> fn:contains(u.username, '1')) > .sorted((u1, u2) -> (x = u1.lastName.compareTo(u2.lastName); > x == 0 ? u1.firstName.compareTo(u2.firstName) : x)) > .map(u -> {'username':u.username, 'first':u.firstName, > 'last':u.lastName}) > .toList()} > > javax.el.ELException: Failed to parse the expression [${users.stream() > .filter(u -> fn:contains(u.username, '1')) > .sorted((u1, u2) -> (x = u1.lastName.compareTo(u2.lastName); > x == 0 ? u1.firstName.compareTo(u2.firstName) : x)) > .map(u -> {'username':u.username, 'first':u.firstName, > 'last':u.lastName}] > ... > <root cause> > org.apache.el.parser.ParseException: Encountered "<EOF>" at line 6, column > 38. Was expecting one of: > "." ... > ")" ... > etc... > > Notice that it thinks the expression is ending after the closing } of the > map-literal. Now the example in 2.3.6.4 of the specification alludes to the > fact that my use of the map-literal here is correct. In that example they use > a list-literal instead (.map(p->[p.name, p.unitPrice])). I tried changing to > use a list-literal instead of a map-literal, and that's when I got the > NumberFormatException described earlier. I _believe_ both should be legal; > the specification clearly intends that at least using the list-literal should > be legal. Neither work in Tomcat. > > Does this make sense? > >>> Section 2.3.6.4 of the specification uses the following example, where a >>> LIST literal is used as the right-hand side of the mapping lambda >>> expression: >>> >>> products.stream().filter(p->p.unitPrice >= 10). >>> .map(p->[p.name, p.unitPrice]) >>> .toList() >>> >>> I tried to use this exact syntax, as shown in the spec, with my example: >>> >>> ${users.stream() >>> .filter(u -> fn:contains(u.username, '1')) >>> .map(u -> [u.username, u.firstName, u.lastName]) >>> .sorted((u1, u2) -> u1.lastName.compareTo(u2.lastName) == 0 ? >>> u1.firstName.compareTo(u2.firstName) : u1.lastName.compareTo(u2.lastName)) >>> .toList()} >>> >>> And now I get this lovely error: >>> >>> javax.el.ELException: java.lang.NumberFormatException: For input string: >>> "lastName" >>> javax.el.BeanELResolver.invoke(BeanELResolver.java:185) >>> >>> org.apache.jasper.el.JasperELResolver.invoke(JasperELResolver.java:147) >>> org.apache.el.parser.AstValue.getValue(AstValue.java:158) >>> ... >>> >>> I'm sure I'm doing something wrong here, but I'm not exactly sure what. On >>> the other hand, it's possible that the Tomcat 8.0 implementation is just >>> wrong. Can someone shed some light on this? >>> >> >> Best regards, >> Konstantin Kolinko > > Thanks, > > Nick --------------------------------------------------------------------- To unsubscribe, e-mail: users-unsubscr...@tomcat.apache.org For additional commands, e-mail: users-h...@tomcat.apache.org