Skip to content

Package: ELContext

ELContext

nameinstructionbranchcomplexitylinemethod
ELContext()
M: 8 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 2 C: 0
0%
M: 1 C: 0
0%
addEvaluationListener(EvaluationListener)
M: 14 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 4 C: 0
0%
M: 1 C: 0
0%
convertToType(Object, Class)
M: 50 C: 0
0%
M: 6 C: 0
0%
M: 4 C: 0
0%
M: 16 C: 0
0%
M: 1 C: 0
0%
enterLambdaScope(Map)
M: 14 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 4 C: 0
0%
M: 1 C: 0
0%
exitLambdaScope()
M: 8 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 3 C: 0
0%
M: 1 C: 0
0%
getContext(Class)
M: 11 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 3 C: 0
0%
M: 1 C: 0
0%
getEvaluationListeners()
M: 3 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
getImportHandler()
M: 11 C: 0
0%
M: 2 C: 0
0%
M: 2 C: 0
0%
M: 3 C: 0
0%
M: 1 C: 0
0%
getLambdaArgument(String)
M: 31 C: 0
0%
M: 6 C: 0
0%
M: 4 C: 0
0%
M: 8 C: 0
0%
M: 1 C: 0
0%
getLocale()
M: 3 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
isLambdaArgument(String)
M: 29 C: 0
0%
M: 6 C: 0
0%
M: 4 C: 0
0%
M: 7 C: 0
0%
M: 1 C: 0
0%
isPropertyResolved()
M: 3 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
notifyAfterEvaluation(String)
M: 21 C: 0
0%
M: 4 C: 0
0%
M: 3 C: 0
0%
M: 6 C: 0
0%
M: 1 C: 0
0%
notifyBeforeEvaluation(String)
M: 21 C: 0
0%
M: 4 C: 0
0%
M: 3 C: 0
0%
M: 6 C: 0
0%
M: 1 C: 0
0%
notifyPropertyResolved(Object, Object)
M: 22 C: 0
0%
M: 4 C: 0
0%
M: 3 C: 0
0%
M: 6 C: 0
0%
M: 1 C: 0
0%
putContext(Class, Object)
M: 15 C: 0
0%
M: 4 C: 0
0%
M: 3 C: 0
0%
M: 4 C: 0
0%
M: 1 C: 0
0%
setLocale(Locale)
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%
setPropertyResolved(Object, Object)
M: 8 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 3 C: 0
0%
M: 1 C: 0
0%
setPropertyResolved(boolean)
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) 1997, 2022 Oracle and/or its affiliates and others.
3: * All rights reserved.
4: * Copyright 2004 The Apache Software Foundation
5: *
6: * Licensed under the Apache License, Version 2.0 (the "License");
7: * you may not use this file except in compliance with the License.
8: * You may obtain a copy of the License at
9: *
10: * http://www.apache.org/licenses/LICENSE-2.0
11: *
12: * Unless required by applicable law or agreed to in writing, software
13: * distributed under the License is distributed on an "AS IS" BASIS,
14: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15: * See the License for the specific language governing permissions and
16: * limitations under the License.
17: */
18:
19: package jakarta.el;
20:
21: import java.util.ArrayList;
22: import java.util.HashMap;
23: import java.util.List;
24: import java.util.Locale;
25: import java.util.Map;
26: import java.util.Stack;
27:
28: /**
29: * Context information for expression parsing and evaluation.
30: *
31: * <p>
32: * To parse or evaluate an {@link Expression}, an <code>ELContext</code> must be provided. The <code>ELContext</code>
33: * holds:
34: * <ul>
35: * <li>a reference to {@link FunctionMapper} that will be used to resolve Jakarta Expression Language Functions. This is
36: * used only in parsing.</li>
37: * <li>a reference to {@link VariableMapper} that will be used to resolve Jakarta Expression Language Variables. This is
38: * used only in parsing.</li>
39: * <li>a reference to the base {@link ELResolver} that will be consulted to resolve model objects and their
40: * properties</li>
41: * <li>a collection of all the relevant context objects for use by <code>ELResolver</code>s</li>
42: * <li>state information during the evaluation of an expression, such as whether a property has been resolved yet</li>
43: * <li>a reference to {@link ImportHandler} that will be consulted to resolve classes that have been imported</li>
44: * <li>a reference to the arguments for the active {@link LambdaExpression}s</li>
45: * <li>a reference to the list of registered evaluation listeners</li>
46: * </ul>
47: *
48: * <p>
49: * The collection of context objects is necessary because each <code>ELResolver</code> may need access to a different
50: * context object. For example, Jakarta Server Pages and Jakarta Faces resolvers need access to a
51: * <code>jakarta.servlet.jsp.JspContext</code> and a <code>jakarta.faces.context.FacesContext</code>, respectively.
52: *
53: * <p>
54: * When used in a web container, the creation of <code>ELContext</code> objects is controlled through the underlying
55: * technology. For example, in Jakarta Server Pages the <code>JspContext.getELContext()</code> factory method is used.
56: * Some technologies provide the ability to add an {@link ELContextListener} so that applications and frameworks can
57: * ensure their own context objects are attached to any newly created <code>ELContext</code>.
58: *
59: * <p>
60: * When used in a stand-alone environment, {@link StandardELContext} provides a default <code>ELContext</code>, which is
61: * managed and modified by {@link ELManager}.
62: *
63: * <p>
64: * Because it stores state during expression evaluation, an <code>ELContext</code> object is not thread-safe. Care
65: * should be taken to never share an <code>ELContext</code> instance between two or more threads.
66: *
67: * @see ELContextListener
68: * @see ELContextEvent
69: * @see ELResolver
70: * @see FunctionMapper
71: * @see VariableMapper
72: * @see ImportHandler
73: * @see LambdaExpression
74: * @see StandardELContext
75: *
76: * @since Jakarta Expression Language 2.1 and Jakarta Expression Language 3.0
77: */
78: public abstract class ELContext {
79:
80: private boolean resolved;
81: private HashMap<Class<?>, Object> map = new HashMap<>();
82: private transient List<EvaluationListener> listeners;
83: private Stack<Map<String, Object>> lambdaArgs;
84: private ImportHandler importHandler;
85: private Locale locale;
86:
87: /**
88: * Called to indicate that a <code>ELResolver</code> has successfully resolved a given (base, property) pair. Use
89: * {@link #setPropertyResolved(Object, Object)} if resolved is true and to notify {@link EvaluationListener}s.
90: *
91: * <p>
92: * The {@link CompositeELResolver} checks this property to determine whether it should consider or skip other component
93: * resolvers.
94: * </p>
95: *
96: * @see CompositeELResolver
97: * @param resolved true if the property has been resolved, or false if not.
98: */
99: public void setPropertyResolved(boolean resolved) {
100: this.resolved = resolved;
101: }
102:
103: /**
104: * Called to indicate that a <code>ELResolver</code> has successfully resolved a given (base, property) pair and to
105: * notify the {@link EvaluationListener}s.
106: *
107: * <p>
108: * The {@link CompositeELResolver} checks this property to determine whether it should consider or skip other component
109: * resolvers.
110: *
111: * @see CompositeELResolver
112: * @param base The base object
113: * @param property The property object
114: *
115: * @since Jakarta Expression Language 3.0
116: */
117: public void setPropertyResolved(Object base, Object property) {
118: setPropertyResolved(true); // Don't set the variable here, for 2.2 users
119: // ELContext may be overridden or delegated.
120: notifyPropertyResolved(base, property);
121: }
122:
123: /**
124: * Returns whether an {@link ELResolver} has successfully resolved a given (base, property) pair.
125: *
126: * <p>
127: * The {@link CompositeELResolver} checks this property to determine whether it should consider or skip other component
128: * resolvers.
129: *
130: * @see CompositeELResolver
131: * @return true if the property has been resolved, or false if not.
132: */
133: public boolean isPropertyResolved() {
134: return resolved;
135: }
136:
137: /**
138: * Associates a context object with this <code>ELContext</code>.
139: *
140: * <p>
141: * The <code>ELContext</code> maintains a collection of context objects relevant to the evaluation of an expression.
142: * These context objects are used by <code>ELResolver</code>s. This method is used to add a context object to that
143: * collection.
144: * </p>
145: *
146: * <p>
147: * By convention, the <code>contextObject</code> will be of the type specified by the <code>key</code>. However, this is
148: * not required and the key is used strictly as a unique identifier.
149: * </p>
150: *
151: * @param key The key used by an @{link ELResolver} to identify this context object.
152: * @param contextObject The context object to add to the collection.
153: * @throws NullPointerException if key is null or contextObject is null.
154: */
155: public void putContext(Class<?> key, Object contextObject) {
156:• if (key == null || contextObject == null) {
157: throw new NullPointerException();
158: }
159:
160: map.put(key, contextObject);
161: }
162:
163: /**
164: * Returns the context object associated with the given key.
165: *
166: * <p>
167: * The <code>ELContext</code> maintains a collection of context objects relevant to the evaluation of an expression.
168: * These context objects are used by <code>ELResolver</code>s. This method is used to retrieve the context with the
169: * given key from the collection.
170: * </p>
171: *
172: * <p>
173: * By convention, the object returned will be of the type specified by the <code>key</code>. However, this is not
174: * required and the key is used strictly as a unique identifier.
175: * </p>
176: *
177: * @param key The unique identifier that was used to associate the context object with this <code>ELContext</code>.
178: * @return The context object associated with the given key, or null if no such context was found.
179: * @throws NullPointerException if key is null.
180: */
181: public Object getContext(Class<?> key) {
182:• if (key == null) {
183: throw new NullPointerException();
184: }
185:
186: return map.get(key);
187: }
188:
189: /**
190: * Retrieves the <code>ELResolver</code> associated with this context.
191: *
192: * <p>
193: * The <code>ELContext</code> maintains a reference to the <code>ELResolver</code> that will be consulted to resolve
194: * variables and properties during an expression evaluation. This method retrieves the reference to the resolver.
195: * </p>
196: *
197: * <p>
198: * Once an <code>ELContext</code> is constructed, the reference to the <code>ELResolver</code> associated with the
199: * context cannot be changed.
200: * </p>
201: *
202: * @return The resolver to be consulted for variable and property resolution during expression evaluation.
203: */
204: public abstract ELResolver getELResolver();
205:
206: /**
207: * Retrieves the <code>ImportHandler</code> associated with this <code>ELContext</code>.
208: *
209: * @return The import handler to manage imports of classes and packages.
210: *
211: * @since Jakarta Expression Language 3.0
212: */
213: public ImportHandler getImportHandler() {
214:• if (importHandler == null) {
215: importHandler = new ImportHandler();
216: }
217:
218: return importHandler;
219: }
220:
221: /**
222: * Retrieves the <code>FunctionMapper</code> associated with this <code>ELContext</code>.
223: *
224: * @return The function mapper to be consulted for the resolution of Jakarta Expression Language functions.
225: */
226: public abstract FunctionMapper getFunctionMapper();
227:
228: /**
229: * Get the <code>Locale</code> stored by a previous invocation to {@link #setLocale}. If this method returns non
230: * <code>null</code>, this <code>Locale</code> must be used for all localization needs in the implementation. The
231: * <code>Locale</code> must not be cached to allow for applications that change <code>Locale</code> dynamically.
232: *
233: * @return The <code>Locale</code> in which this instance is operating. Used primarily for message localization.
234: */
235: public Locale getLocale() {
236: return locale;
237: }
238:
239: /**
240: * Sets the <code>Locale</code> for this instance.
241: *
242: * <p>
243: * This method may be called by the party creating the instance, such as Jakarta Faces or Jakarta Server Pages, to
244: * enable the Jakarta Expression Language implementation to provide localized messages to the user. If no
245: * <code>Locale</code> is set, the implementation must use the locale returned by <code>Locale.getDefault( )</code>.
246: *
247: * @param locale the locale for this instance
248: */
249: public void setLocale(Locale locale) {
250: this.locale = locale;
251: }
252:
253: /**
254: * Retrieves the <code>VariableMapper</code> associated with this <code>ELContext</code>.
255: *
256: * @return The variable mapper to be consulted for the resolution of Jakarta Expression Language variables.
257: */
258: public abstract VariableMapper getVariableMapper();
259:
260: /**
261: * Registers an evaluation listener to the ELContext.
262: *
263: * @param listener The listener to be added.
264: *
265: * @since Jakarta Expression Language 3.0
266: */
267: public void addEvaluationListener(EvaluationListener listener) {
268:• if (listeners == null) {
269: listeners = new ArrayList<>();
270: }
271:
272: listeners.add(listener);
273: }
274:
275: /**
276: * Returns the list of registered evaluation listeners.
277: *
278: * @return The list of registered evaluation listeners.
279: *
280: * @since Jakarta Expression Language 3.0
281: */
282: public List<EvaluationListener> getEvaluationListeners() {
283: return listeners;
284: }
285:
286: /**
287: * Notifies the listeners before an Jakarta Expression Language expression is evaluated
288: *
289: * @param expr The Jakarta Expression Language expression string to be evaluated
290: */
291: public void notifyBeforeEvaluation(String expr) {
292:• if (getEvaluationListeners() == null) {
293: return;
294: }
295:
296:• for (EvaluationListener listener : getEvaluationListeners()) {
297: listener.beforeEvaluation(this, expr);
298: }
299: }
300:
301: /**
302: * Notifies the listeners after an Jakarta Expression Language expression is evaluated
303: *
304: * @param expr The Jakarta Expression Language expression string that has been evaluated
305: */
306: public void notifyAfterEvaluation(String expr) {
307:• if (getEvaluationListeners() == null) {
308: return;
309: }
310:
311:• for (EvaluationListener listener : getEvaluationListeners()) {
312: listener.afterEvaluation(this, expr);
313: }
314: }
315:
316: /**
317: * Notifies the listeners when the (base, property) pair is resolved
318: *
319: * @param base The base object
320: * @param property The property Object
321: */
322: public void notifyPropertyResolved(Object base, Object property) {
323:• if (getEvaluationListeners() == null) {
324: return;
325: }
326:
327:• for (EvaluationListener listener : getEvaluationListeners()) {
328: listener.propertyResolved(this, base, property);
329: }
330: }
331:
332: /**
333: * Inquires if the name is a LambdaArgument
334: *
335: * @param arg A possible Lambda formal parameter name
336: * @return true if arg is a LambdaArgument, false otherwise.
337: */
338: public boolean isLambdaArgument(String arg) {
339:• if (lambdaArgs == null) {
340: return false;
341: }
342:
343:• for (int i = lambdaArgs.size() - 1; i >= 0; i--) {
344: Map<String, Object> lmap = lambdaArgs.elementAt(i);
345:• if (lmap.containsKey(arg)) {
346: return true;
347: }
348: }
349:
350: return false;
351: }
352:
353: /**
354: * Retrieves the Lambda argument associated with a formal parameter. If the Lambda expression is nested within other
355: * Lambda expressions, the arguments for the current Lambda expression is first searched, and if not found, the
356: * arguments for the immediate nesting Lambda expression then searched, and so on.
357: *
358: * @param arg The formal parameter for the Lambda argument
359: * @return The object associated with formal parameter. Null if no object has been associated with the parameter.
360: *
361: * @since Jakarta Expression Language 3.0
362: */
363: public Object getLambdaArgument(String arg) {
364:• if (lambdaArgs == null) {
365: return null;
366: }
367:
368:• for (int i = lambdaArgs.size() - 1; i >= 0; i--) {
369: Map<String, Object> lmap = lambdaArgs.elementAt(i);
370: Object v = lmap.get(arg);
371:• if (v != null) {
372: return v;
373: }
374: }
375:
376: return null;
377: }
378:
379: /**
380: * Installs a Lambda argument map, in preparation for the evaluation of a Lambda expression. The arguments in the map
381: * will be in scope during the evaluation of the Lambda expression.
382: *
383: * @param args The Lambda arguments map
384: *
385: * @since Jakarta Expression Language 3.0
386: */
387: public void enterLambdaScope(Map<String, Object> args) {
388:• if (lambdaArgs == null) {
389: lambdaArgs = new Stack<>();
390: }
391:
392: lambdaArgs.push(args);
393: }
394:
395: /**
396: * Exits the Lambda expression evaluation. The Lambda argument map that was previously installed is removed.
397: *
398: * @since Jakarta Expression Language 3.0
399: */
400: public void exitLambdaScope() {
401:• if (lambdaArgs != null) {
402: lambdaArgs.pop();
403: }
404: }
405:
406: /**
407: * Converts an object to a specific type. If a custom converter in the <code>ELResolver</code> handles this conversion,
408: * it is used. Otherwise the standard coercions is applied.
409: *
410: * <p>
411: * An <code>ELException</code> is thrown if an error occurs during the conversion.
412: *
413: * @param obj The object to convert.
414: * @param targetType The target type for the conversion.
415: *
416: * @return object converted to <code>targetType</code>
417: * @throws ELException thrown if errors occur.
418: *
419: * @since Jakarta Expression Language 3.0
420: */
421: public <T> T convertToType(Object obj, Class<T> targetType) {
422: boolean propertyResolvedSave = isPropertyResolved();
423: try {
424: setPropertyResolved(false);
425: ELResolver elResolver = getELResolver();
426:• if (elResolver != null) {
427: T res = elResolver.convertToType(this, obj, targetType);
428:• if (isPropertyResolved()) {
429: return res;
430: }
431: }
432: } catch (ELException ex) {
433: throw ex;
434: } catch (Exception ex) {
435: throw new ELException(ex);
436: } finally {
437: setPropertyResolved(propertyResolvedSave);
438: }
439:
440: ExpressionFactory exprFactory = (ExpressionFactory) getContext(ExpressionFactory.class);
441:• if (exprFactory == null) {
442: exprFactory = ELManager.getExpressionFactory();
443: }
444:
445: return exprFactory.coerceToType(obj, targetType);
446: }
447:
448: }