Skip to content

Package: LambdaExpression

LambdaExpression

nameinstructionbranchcomplexitylinemethod
LambdaExpression(List, ValueExpression)
M: 19 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 6 C: 0
0%
M: 1 C: 0
0%
invoke(ELContext, Object[])
M: 62 C: 0
0%
M: 6 C: 0
0%
M: 4 C: 0
0%
M: 14 C: 0
0%
M: 1 C: 0
0%
invoke(Object[])
M: 6 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
setELContext(ELContext)
M: 4 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 2 C: 0
0%
M: 1 C: 0
0%

Coverage

1: /*
2: * Copyright (c) 2012, 2019 Oracle and/or its affiliates and others.
3: * All rights reserved.
4: *
5: * This program and the accompanying materials are made available under the
6: * terms of the Eclipse Public License v. 2.0, which is available at
7: * http://www.eclipse.org/legal/epl-2.0.
8: *
9: * This Source Code may also be made available under the following Secondary
10: * Licenses when the conditions for such availability set forth in the
11: * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
12: * version 2 with the GNU Classpath Exception, which is available at
13: * https://www.gnu.org/software/classpath/license.html.
14: *
15: * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
16: */
17:
18: package jakarta.el;
19:
20: import java.util.ArrayList;
21: import java.util.HashMap;
22: import java.util.List;
23: import java.util.Map;
24:
25: /**
26: * Encapsulates a parameterized {@link ValueExpression}.
27: *
28: * <p>
29: * A <code>LambdaExpression</code> is a representation of the Jakarta Expression Language Lambda expression syntax. It
30: * consists of a list of the formal parameters and a body, represented by a {@link ValueExpression}. The body can be any
31: * valid <code>Expression</code>, including another <code>LambdaExpression</code>.
32: *
33: * <p>
34: * A <code>LambdaExpression</code> is created when an Jakarta Expression Language expression containing a Lambda
35: * expression is evaluated.
36: *
37: * <p>
38: * A <code>LambdaExpression</code> can be invoked by calling {@link LambdaExpression#invoke}, with an
39: * {@link ELContext} and a list of the actual arguments. Alternately, a <code>LambdaExpression</code> can be
40: * invoked without passing a <code>ELContext</code>, in which case the <code>ELContext</code> previously set by calling
41: * {@link LambdaExpression#setELContext} will be used. The evaluation of the <code>ValueExpression</code> in the body
42: * uses the {@link ELContext} to resolve references to the parameters, and to evaluate the lambda expression. The result
43: * of the evaluation is returned.
44: *
45: * @see ELContext#getLambdaArgument
46: * @see ELContext#enterLambdaScope
47: * @see ELContext#exitLambdaScope
48: */
49: public class LambdaExpression {
50:
51: private List<String> formalParameters = new ArrayList<>();
52: private ValueExpression expression;
53: private ELContext context;
54: // Arguments from nesting lambdas, when the body is another lambda
55: private Map<String, Object> envirArgs;
56:
57: /**
58: * Creates a new LambdaExpression.
59: *
60: * @param formalParameters The list of String representing the formal parameters.
61: * @param expression The <code>ValueExpression</code> representing the body.
62: */
63: public LambdaExpression(List<String> formalParameters, ValueExpression expression) {
64: this.formalParameters = formalParameters;
65: this.expression = expression;
66: this.envirArgs = new HashMap<>();
67: }
68:
69: /**
70: * Set the ELContext to use in evaluating the LambdaExpression. The ELContext must to be set prior to the invocation of
71: * the LambdaExpression, unless it is supplied with {@link LambdaExpression#invoke}.
72: *
73: * @param context The ELContext to use in evaluating the LambdaExpression.
74: */
75: public void setELContext(ELContext context) {
76: this.context = context;
77: }
78:
79: /**
80: * Invoke the encapsulated Lambda expression.
81: * <p>
82: * The supplied arguments are matched, in the same order, to the formal parameters. If there are more arguments than the
83: * formal parameters, the extra arguments are ignored. If there are less arguments than the formal parameters, an
84: * <code>ELException</code> is thrown.
85: * </p>
86: *
87: * <p>
88: * The actual Lambda arguments are added to the ELContext and are available during the evaluation of the Lambda
89: * expression. They are removed after the evaluation.
90: * </p>
91: *
92: * @param elContext The ELContext used for the evaluation of the expression The ELContext set by {@link #setELContext}
93: * is ignored.
94: * @param args The arguments to invoke the Lambda expression. For calls with no arguments, an empty array must be
95: * provided. A Lambda argument can be <code>null</code>.
96: * @return The result of invoking the Lambda expression
97: * @throws ELException if not enough arguments are provided
98: * @throws NullPointerException is elContext is null
99: */
100: public Object invoke(ELContext elContext, Object... args) throws ELException {
101: int i = 0;
102: Map<String, Object> lambdaArgs = new HashMap<>();
103:
104: // First get arguments injected from the outter lambda, if any
105: lambdaArgs.putAll(envirArgs);
106:
107:• for (String fParam : formalParameters) {
108:• if (i >= args.length) {
109: throw new ELException("Expected Argument " + fParam + " missing in Lambda Expression");
110: }
111: lambdaArgs.put(fParam, args[i++]);
112: }
113:
114: elContext.enterLambdaScope(lambdaArgs);
115: try {
116: Object ret = expression.getValue(elContext);
117:
118: // If the result of evaluating the body is another LambdaExpression,
119: // whose body has not been evaluated yet. (A LambdaExpression is
120: // evaluated iff when its invoke method is called.) The current lambda
121: // arguments may be needed in that body when it is evaluated later,
122: // after the current lambda exits. To make these arguments available
123: // then, they are injected into it.
124:• if (ret instanceof LambdaExpression) {
125: ((LambdaExpression) ret).envirArgs.putAll(lambdaArgs);
126: }
127: return ret;
128: } finally {
129: elContext.exitLambdaScope();
130: }
131:
132:
133: }
134:
135: /**
136: * Invoke the encapsulated Lambda expression.
137: * <p>
138: * The supplied arguments are matched, in the same order, to the formal parameters. If there are more arguments than the
139: * formal parameters, the extra arguments are ignored. If there are less arguments than the formal parameters, an
140: * <code>ELException</code> is thrown.
141: * </p>
142: *
143: * <p>
144: * The actual Lambda arguments are added to the ELContext and are available during the evaluation of the Lambda
145: * expression. They are removed after the evaluation.
146: * </p>
147: *
148: * The ELContext set by {@link LambdaExpression#setELContext} is used in the evaluation of the lambda Expression.
149: *
150: * @param args The arguments to invoke the Lambda expression. For calls with no arguments, an empty array must be
151: * provided. A Lambda argument can be <code>null</code>.
152: * @return The result of invoking the Lambda expression
153: * @throws ELException if not enough arguments are provided
154: */
155: public Object invoke(Object... args) {
156: return invoke(context, args);
157: }
158: }