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