Search code examples
javaspringjava-8spring-el

Spring Expression Language - Java 8 forEach or stream on list


Is it possible for stream or forEach on list in SpEL? e.g.

List<String> x = new LinkedList<>(Arrays.asList("A","AAB"));
ExpressionParser parser = new SpelExpressionParser();
StandardEvaluationContext context = new StandardEvaluationContext(x);
parser.parseExpression("x.stream().map(x -> x.replaceAll(\"A\", \"B\")).collect(Collectors.toList())").getValue(context))

Solution

  • SpEL is not Java, it's a different language; the acronym stands for Spring Expression Language.

    It doesn't understand Java8 lambdas so can't parse x -> ....

    Also, static methods are invoked with the T operator.

    So, this works...

    List<String> x = new LinkedList<>(Arrays.asList("A","AAB"));
    ExpressionParser parser = new SpelExpressionParser();
    Expression expression = parser.parseExpression("stream().collect(T(java.util.stream.Collectors).toList())");
    System.out.println(expression.getValue(x));
    

    (but it's not very useful).

    You can use streams, but only with simple methods that don't take lambdas...

    Expression expression = parser.parseExpression("stream().findFirst().get()");
    Expression expression = parser.parseExpression("stream().count()");
    

    or

    List<String> x = new LinkedList<>(Arrays.asList("A","AAB", "A"));
    ExpressionParser parser = new SpelExpressionParser();
    Expression expression = parser.parseExpression("stream().distinct().collect(T(java.util.stream.Collectors).toList())");
    System.out.println(expression.getValue(x));
    

    etc

    EDIT

    You can, however, register lambdas as SpEL #functions, so this works fine...

    public class So48840190Application {
    
        public static void main(String[] args) throws Exception {
            List<String> x = new LinkedList<>(Arrays.asList("A","AAB", "A"));
            ExpressionParser parser = new SpelExpressionParser();
            StandardEvaluationContext ec = new StandardEvaluationContext();
            ec.registerFunction("aToB", So48840190Application.class.getMethod("aToB"));
            Expression expression = parser.parseExpression(
                    "stream().map(#aToB()).collect(T(java.util.stream.Collectors).toList())");
            System.out.println(expression.getValue(ec, x));
        }
    
        public static Function<String, String> aToB() {
            return s -> s.replaceAll("A", "B");
        }
    
    }
    

    and

    [B, BBB, B]
    

    EDIT2

    Or, more generally...

    public class So48840190Application {
    
        public static void main(String[] args) throws Exception {
            List<String> x = new LinkedList<>(Arrays.asList("A","AAB", "A"));
            ExpressionParser parser = new SpelExpressionParser();
            StandardEvaluationContext ec = new StandardEvaluationContext();
            ec.registerFunction("replaceAll",
                    So48840190Application.class.getMethod("replaceAll", String.class, String.class));
            ec.registerFunction("toLowerCase",
                    So48840190Application.class.getMethod("toLowerCase"));
            Expression expression = parser.parseExpression(
                    "stream().map(#replaceAll('A', 'B')).map(#toLowerCase()).collect(T(java.util.stream.Collectors).toList())");
            System.out.println(expression.getValue(ec, x));
        }
    
        public static Function<String, String> replaceAll(String from, String to) {
            return s -> s.replaceAll(from, to);
        }
    
        public static Function<String, String> toLowerCase() {
            return String::toLowerCase;
        }
    
    }