Skip to content

Package: ListELResolver

ListELResolver

nameinstructionbranchcomplexitylinemethod
ListELResolver()
M: 6 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 3 C: 0
0%
M: 1 C: 0
0%
ListELResolver(boolean)
M: 6 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 3 C: 0
0%
M: 1 C: 0
0%
getCommonPropertyType(ELContext, Object)
M: 9 C: 0
0%
M: 4 C: 0
0%
M: 3 C: 0
0%
M: 3 C: 0
0%
M: 1 C: 0
0%
getFeatureDescriptors(ELContext, Object)
M: 2 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
getType(ELContext, Object, Object)
M: 44 C: 0
0%
M: 14 C: 0
0%
M: 8 C: 0
0%
M: 12 C: 0
0%
M: 1 C: 0
0%
getValue(ELContext, Object, Object)
M: 36 C: 0
0%
M: 10 C: 0
0%
M: 6 C: 0
0%
M: 10 C: 0
0%
M: 1 C: 0
0%
isReadOnly(ELContext, Object, Object)
M: 44 C: 0
0%
M: 14 C: 0
0%
M: 8 C: 0
0%
M: 10 C: 0
0%
M: 1 C: 0
0%
setValue(ELContext, Object, Object, Object)
M: 55 C: 0
0%
M: 8 C: 0
0%
M: 5 C: 0
0%
M: 21 C: 0
0%
M: 1 C: 0
0%
static {...}
M: 7 C: 0
0%
M: 0 C: 0
100%
M: 1 C: 0
0%
M: 1 C: 0
0%
M: 1 C: 0
0%
toInteger(Object)
M: 32 C: 0
0%
M: 8 C: 0
0%
M: 5 C: 0
0%
M: 9 C: 0
0%
M: 1 C: 0
0%

Coverage

1: /*
2: * Copyright (c) 1997, 2021 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.beans.FeatureDescriptor;
22: import java.util.ArrayList;
23: import java.util.Collections;
24: import java.util.Iterator;
25: import java.util.List;
26:
27: /**
28: * Defines property resolution behavior on instances of {@link java.util.List}.
29: *
30: * <p>
31: * This resolver handles base objects of type <code>java.util.List</code>. It accepts any object as a property and
32: * coerces that object into an integer index into the list. The resulting value is the value in the list at that index.
33: * </p>
34: *
35: * <p>
36: * This resolver can be constructed in read-only mode, which means that {@link #isReadOnly} will always return
37: * <code>true</code> and {@link #setValue} will always throw <code>PropertyNotWritableException</code>.
38: * </p>
39: *
40: * <p>
41: * <code>ELResolver</code>s are combined together using {@link CompositeELResolver}s, to define rich semantics for
42: * evaluating an expression. See the javadocs for {@link ELResolver} for details.
43: * </p>
44: *
45: * @see CompositeELResolver
46: * @see ELResolver
47: * @see java.util.List
48: * @since Jakarta Server Pages 2.1
49: */
50: public class ListELResolver extends ELResolver {
51:
52: static private Class<?> theUnmodifiableListClass = Collections.unmodifiableList(new ArrayList<>()).getClass();
53: private boolean isReadOnly;
54:
55: /**
56: * Creates a new read/write <code>ListELResolver</code>.
57: */
58: public ListELResolver() {
59: isReadOnly = false;
60: }
61:
62: /**
63: * Creates a new <code>ListELResolver</code> whose read-only status is determined by the given parameter.
64: *
65: * @param isReadOnly <code>true</code> if this resolver cannot modify lists; <code>false</code> otherwise.
66: */
67: public ListELResolver(boolean isReadOnly) {
68: this.isReadOnly = isReadOnly;
69: }
70:
71: /**
72: * If the base object is a list, returns the most general acceptable type for a value in this list.
73: *
74: * <p>
75: * If the base is a <code>List</code>, the <code>propertyResolved</code> property of the <code>ELContext</code> object
76: * must be set to <code>true</code> by this resolver, before returning. If this property is not <code>true</code> after
77: * this method is called, the caller should ignore the return value.
78: * </p>
79: *
80: * <p>
81: * Assuming the base is a <code>List</code>, this method will return <code>Object.class</code> unless the resolver
82: * is constructed in read-only mode in which case {@code null} will be returned. This is because <code>List</code>s
83: * accept any object as an element.
84: * </p>
85: *
86: * @param context The context of this evaluation.
87: * @param base The list to analyze. Only bases of type <code>List</code> are handled by this resolver.
88: * @param property The index of the element in the list to return the acceptable type for. Will be coerced into an
89: * integer, but otherwise ignored by this resolver.
90: * @return If the <code>propertyResolved</code> property of <code>ELContext</code> was set to <code>true</code>, then
91: * the most general acceptable type which must be {@code null} if the either the property or the resolver is
92: * read-only; otherwise undefined
93: * @throws PropertyNotFoundException if the given index is out of bounds for this list.
94: * @throws NullPointerException if context is <code>null</code>
95: * @throws ELException if an exception was thrown while performing the property or variable resolution. The thrown
96: * exception must be included as the cause property of this exception, if available.
97: */
98: @Override
99: public Class<?> getType(ELContext context, Object base, Object property) {
100:• if (context == null) {
101: throw new NullPointerException();
102: }
103:
104:• if (base != null && base instanceof List) {
105: context.setPropertyResolved(true);
106: List<?> list = (List<?>) base;
107: int index = toInteger(property);
108:• if (index < 0 || index >= list.size()) {
109: throw new PropertyNotFoundException();
110: }
111:
112: /*
113: * Not perfect as a custom list implementation may be read-only but
114: * consistent with isReadOnly().
115: */
116:• if (list.getClass() == theUnmodifiableListClass || isReadOnly) {
117: return null;
118: }
119:
120: return Object.class;
121: }
122:
123: return null;
124: }
125:
126: /**
127: * If the base object is a list, returns the value at the given index. The index is specified by the
128: * <code>property</code> argument, and coerced into an integer. If the coercion could not be performed, an
129: * <code>IllegalArgumentException</code> is thrown. If the index is out of bounds, <code>null</code> is returned.
130: *
131: * <p>
132: * If the base is a <code>List</code>, the <code>propertyResolved</code> property of the <code>ELContext</code> object
133: * must be set to <code>true</code> by this resolver, before returning. If this property is not <code>true</code> after
134: * this method is called, the caller should ignore the return value.
135: * </p>
136: *
137: * @param context The context of this evaluation.
138: * @param base The list to be analyzed. Only bases of type <code>List</code> are handled by this resolver.
139: * @param property The index of the value to be returned. Will be coerced into an integer.
140: * @return If the <code>propertyResolved</code> property of <code>ELContext</code> was set to <code>true</code>, then
141: * the value at the given index or <code>null</code> if the index was out of bounds. Otherwise, undefined.
142: * @throws IllegalArgumentException if the property could not be coerced into an integer.
143: * @throws NullPointerException if context is <code>null</code>.
144: * @throws ELException if an exception was thrown while performing the property or variable resolution. The thrown
145: * exception must be included as the cause property of this exception, if available.
146: */
147: @Override
148: public Object getValue(ELContext context, Object base, Object property) {
149:• if (context == null) {
150: throw new NullPointerException();
151: }
152:
153:• if (base != null && base instanceof List) {
154: context.setPropertyResolved(base, property);
155: List<?> list = (List<?>) base;
156: int index = toInteger(property);
157:• if (index < 0 || index >= list.size()) {
158: return null;
159: }
160:
161: return list.get(index);
162: }
163:
164: return null;
165: }
166:
167: /**
168: * If the base object is a list, attempts to set the value at the given index with the given value. The index is
169: * specified by the <code>property</code> argument, and coerced into an integer. If the coercion could not be performed,
170: * an <code>IllegalArgumentException</code> is thrown. If the index is out of bounds, a
171: * <code>PropertyNotFoundException</code> is thrown.
172: *
173: * <p>
174: * If the base is a <code>List</code>, the <code>propertyResolved</code> property of the <code>ELContext</code> object
175: * must be set to <code>true</code> by this resolver, before returning. If this property is not <code>true</code> after
176: * this method is called, the caller can safely assume no value was set.
177: * </p>
178: *
179: * <p>
180: * If this resolver was constructed in read-only mode, this method will always throw
181: * <code>PropertyNotWritableException</code>.
182: * </p>
183: *
184: * <p>
185: * If a <code>List</code> was created using {@link java.util.Collections#unmodifiableList}, this method must throw
186: * <code>PropertyNotWritableException</code>. Unfortunately, there is no Collections API method to detect this. However,
187: * an implementation can create a prototype unmodifiable <code>List</code> and query its runtime type to see if it
188: * matches the runtime type of the base object as a workaround.
189: * </p>
190: *
191: * @param context The context of this evaluation.
192: * @param base The list to be modified. Only bases of type <code>List</code> are handled by this resolver.
193: * @param property The index of the value to be set. Will be coerced into an integer.
194: * @param val The value to be set at the given index.
195: * @throws ClassCastException if the class of the specified element prevents it from being added to this list.
196: * @throws NullPointerException if context is <code>null</code>, or if the value is <code>null</code> and this
197: * <code>List</code> does not support <code>null</code> elements.
198: * @throws IllegalArgumentException if the property could not be coerced into an integer, or if some aspect of the
199: * specified element prevents it from being added to this list.
200: * @throws PropertyNotWritableException if this resolver was constructed in read-only mode, or if the set operation is
201: * not supported by the underlying list.
202: * @throws PropertyNotFoundException if the given index is out of bounds for this list.
203: * @throws ELException if an exception was thrown while performing the property or variable resolution. The thrown
204: * exception must be included as the cause property of this exception, if available.
205: */
206: @Override
207: public void setValue(ELContext context, Object base, Object property, Object val) {
208:• if (context == null) {
209: throw new NullPointerException();
210: }
211:
212:• if (base != null && base instanceof List) {
213: context.setPropertyResolved(base, property);
214: // Safe cast
215: @SuppressWarnings("unchecked")
216: List<Object> list = (List<Object>) base;
217: int index = toInteger(property);
218:• if (isReadOnly) {
219: throw new PropertyNotWritableException();
220: }
221:
222: try {
223: list.set(index, val);
224: } catch (UnsupportedOperationException ex) {
225: throw new PropertyNotWritableException();
226: } catch (IndexOutOfBoundsException ex) {
227: throw new PropertyNotFoundException();
228: } catch (ClassCastException ex) {
229: throw ex;
230: } catch (NullPointerException ex) {
231: throw ex;
232: } catch (IllegalArgumentException ex) {
233: throw ex;
234: }
235: }
236: }
237:
238: /**
239: * If the base object is a list, returns whether a call to {@link #setValue} will always fail.
240: *
241: * <p>
242: * If the base is a <code>List</code>, the <code>propertyResolved</code> property of the <code>ELContext</code> object
243: * must be set to <code>true</code> by this resolver, before returning. If this property is not <code>true</code> after
244: * this method is called, the caller should ignore the return value.
245: * </p>
246: *
247: * <p>
248: * If this resolver was constructed in read-only mode, this method will always return <code>true</code>.
249: * </p>
250: *
251: * <p>
252: * If a <code>List</code> was created using {@link java.util.Collections#unmodifiableList}, this method must return
253: * <code>true</code>. Unfortunately, there is no Collections API method to detect this. However, an implementation can
254: * create a prototype unmodifiable <code>List</code> and query its runtime type to see if it matches the runtime type of
255: * the base object as a workaround.
256: * </p>
257: *
258: * @param context The context of this evaluation.
259: * @param base The list to analyze. Only bases of type <code>List</code> are handled by this resolver.
260: * @param property The index of the element in the list to return the acceptable type for. Will be coerced into an
261: * integer, but otherwise ignored by this resolver.
262: * @return If the <code>propertyResolved</code> property of <code>ELContext</code> was set to <code>true</code>, then
263: * <code>true</code> if calling the <code>setValue</code> method will always fail or <code>false</code> if it is
264: * possible that such a call may succeed; otherwise undefined.
265: * @throws PropertyNotFoundException if the given index is out of bounds for this list.
266: * @throws NullPointerException if context is <code>null</code>
267: * @throws ELException if an exception was thrown while performing the property or variable resolution. The thrown
268: * exception must be included as the cause property of this exception, if available.
269: */
270: @Override
271: public boolean isReadOnly(ELContext context, Object base, Object property) {
272:• if (context == null) {
273: throw new NullPointerException();
274: }
275:
276:• if (base != null && base instanceof List) {
277: context.setPropertyResolved(true);
278: List<?> list = (List<?>) base;
279: int index = toInteger(property);
280:• if (index < 0 || index >= list.size()) {
281: throw new PropertyNotFoundException();
282: }
283:
284:• return list.getClass() == theUnmodifiableListClass || isReadOnly;
285: }
286:
287: return false;
288: }
289:
290: /**
291: * Always returns <code>null</code>, since there is no reason to iterate through set set of all integers.
292: *
293: * <p>
294: * The {@link #getCommonPropertyType} method returns sufficient information about what properties this resolver accepts.
295: * </p>
296: *
297: * @param context The context of this evaluation.
298: * @param base The list. Only bases of type <code>List</code> are handled by this resolver.
299: * @return <code>null</code>.
300: *
301: * @deprecated This method will be removed without replacement in EL 6.0
302: */
303: @Deprecated(forRemoval = true, since = "5.0")
304: @Override
305: public Iterator<FeatureDescriptor> getFeatureDescriptors(ELContext context, Object base) {
306: return null;
307: }
308:
309: /**
310: * If the base object is a list, returns the most general type that this resolver accepts for the <code>property</code>
311: * argument. Otherwise, returns <code>null</code>.
312: *
313: * <p>
314: * Assuming the base is a <code>List</code>, this method will always return <code>Integer.class</code>. This is because
315: * <code>List</code>s accept integers as their index.
316: * </p>
317: *
318: * @param context The context of this evaluation.
319: * @param base The list to analyze. Only bases of type <code>List</code> are handled by this resolver.
320: * @return <code>null</code> if base is not a <code>List</code> otherwise <code>Integer.class</code>.
321: */
322: @Override
323: public Class<?> getCommonPropertyType(ELContext context, Object base) {
324:• if (base != null && base instanceof List) {
325: return Integer.class;
326: }
327:
328: return null;
329: }
330:
331: private int toInteger(Object p) {
332:• if (p instanceof Integer) {
333: return ((Integer) p).intValue();
334: }
335:• if (p instanceof Character) {
336: return ((Character) p).charValue();
337: }
338:• if (p instanceof Number) {
339: return ((Number) p).intValue();
340: }
341:• if (p instanceof String) {
342: return Integer.parseInt((String) p);
343: }
344: throw new IllegalArgumentException();
345: }
346: }