Package: ListELResolver
ListELResolver
name | instruction | branch | complexity | line | method | ||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
ListELResolver() |
|
|
|
|
|
||||||||||||||||||||
ListELResolver(boolean) |
|
|
|
|
|
||||||||||||||||||||
getCommonPropertyType(ELContext, Object) |
|
|
|
|
|
||||||||||||||||||||
getFeatureDescriptors(ELContext, Object) |
|
|
|
|
|
||||||||||||||||||||
getType(ELContext, Object, Object) |
|
|
|
|
|
||||||||||||||||||||
getValue(ELContext, Object, Object) |
|
|
|
|
|
||||||||||||||||||||
isReadOnly(ELContext, Object, Object) |
|
|
|
|
|
||||||||||||||||||||
setValue(ELContext, Object, Object, Object) |
|
|
|
|
|
||||||||||||||||||||
static {...} |
|
|
|
|
|
||||||||||||||||||||
toInteger(Object) |
|
|
|
|
|
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 always return <code>Object.class</code>. This is because
82: * <code>List</code>s accept any object as an element.
83: * </p>
84: *
85: * @param context The context of this evaluation.
86: * @param base The list to analyze. Only bases of type <code>List</code> are handled by this resolver.
87: * @param property The index of the element in the list to return the acceptable type for. Will be coerced into an
88: * integer, but otherwise ignored by this resolver.
89: * @return If the <code>propertyResolved</code> property of <code>ELContext</code> was set to <code>true</code>, then
90: * the most general acceptable type; otherwise undefined.
91: * @throws PropertyNotFoundException if the given index is out of bounds for this list.
92: * @throws NullPointerException if context is <code>null</code>
93: * @throws ELException if an exception was thrown while performing the property or variable resolution. The thrown
94: * exception must be included as the cause property of this exception, if available.
95: */
96: @Override
97: public Class<?> getType(ELContext context, Object base, Object property) {
98:• if (context == null) {
99: throw new NullPointerException();
100: }
101:
102:• if (base != null && base instanceof List) {
103: context.setPropertyResolved(true);
104: List<?> list = (List<?>) base;
105: int index = toInteger(property);
106:• if (index < 0 || index >= list.size()) {
107: throw new PropertyNotFoundException();
108: }
109:
110: return Object.class;
111: }
112:
113: return null;
114: }
115:
116: /**
117: * If the base object is a list, returns the value at the given index. The index is specified by the
118: * <code>property</code> argument, and coerced into an integer. If the coercion could not be performed, an
119: * <code>IllegalArgumentException</code> is thrown. If the index is out of bounds, <code>null</code> is returned.
120: *
121: * <p>
122: * If the base is a <code>List</code>, the <code>propertyResolved</code> property of the <code>ELContext</code> object
123: * must be set to <code>true</code> by this resolver, before returning. If this property is not <code>true</code> after
124: * this method is called, the caller should ignore the return value.
125: * </p>
126: *
127: * @param context The context of this evaluation.
128: * @param base The list to be analyzed. Only bases of type <code>List</code> are handled by this resolver.
129: * @param property The index of the value to be returned. Will be coerced into an integer.
130: * @return If the <code>propertyResolved</code> property of <code>ELContext</code> was set to <code>true</code>, then
131: * the value at the given index or <code>null</code> if the index was out of bounds. Otherwise, undefined.
132: * @throws IllegalArgumentException if the property could not be coerced into an integer.
133: * @throws NullPointerException if context is <code>null</code>.
134: * @throws ELException if an exception was thrown while performing the property or variable resolution. The thrown
135: * exception must be included as the cause property of this exception, if available.
136: */
137: @Override
138: public Object getValue(ELContext context, Object base, Object property) {
139:• if (context == null) {
140: throw new NullPointerException();
141: }
142:
143:• if (base != null && base instanceof List) {
144: context.setPropertyResolved(base, property);
145: List<?> list = (List<?>) base;
146: int index = toInteger(property);
147:• if (index < 0 || index >= list.size()) {
148: return null;
149: }
150:
151: return list.get(index);
152: }
153:
154: return null;
155: }
156:
157: /**
158: * If the base object is a list, attempts to set the value at the given index with the given value. The index is
159: * specified by the <code>property</code> argument, and coerced into an integer. If the coercion could not be performed,
160: * an <code>IllegalArgumentException</code> is thrown. If the index is out of bounds, a
161: * <code>PropertyNotFoundException</code> is thrown.
162: *
163: * <p>
164: * If the base is a <code>List</code>, the <code>propertyResolved</code> property of the <code>ELContext</code> object
165: * must be set to <code>true</code> by this resolver, before returning. If this property is not <code>true</code> after
166: * this method is called, the caller can safely assume no value was set.
167: * </p>
168: *
169: * <p>
170: * If this resolver was constructed in read-only mode, this method will always throw
171: * <code>PropertyNotWritableException</code>.
172: * </p>
173: *
174: * <p>
175: * If a <code>List</code> was created using {@link java.util.Collections#unmodifiableList}, this method must throw
176: * <code>PropertyNotWritableException</code>. Unfortunately, there is no Collections API method to detect this. However,
177: * an implementation can create a prototype unmodifiable <code>List</code> and query its runtime type to see if it
178: * matches the runtime type of the base object as a workaround.
179: * </p>
180: *
181: * @param context The context of this evaluation.
182: * @param base The list to be modified. Only bases of type <code>List</code> are handled by this resolver.
183: * @param property The index of the value to be set. Will be coerced into an integer.
184: * @param val The value to be set at the given index.
185: * @throws ClassCastException if the class of the specified element prevents it from being added to this list.
186: * @throws NullPointerException if context is <code>null</code>, or if the value is <code>null</code> and this
187: * <code>List</code> does not support <code>null</code> elements.
188: * @throws IllegalArgumentException if the property could not be coerced into an integer, or if some aspect of the
189: * specified element prevents it from being added to this list.
190: * @throws PropertyNotWritableException if this resolver was constructed in read-only mode, or if the set operation is
191: * not supported by the underlying list.
192: * @throws PropertyNotFoundException if the given index is out of bounds for this list.
193: * @throws ELException if an exception was thrown while performing the property or variable resolution. The thrown
194: * exception must be included as the cause property of this exception, if available.
195: */
196: @Override
197: public void setValue(ELContext context, Object base, Object property, Object val) {
198:• if (context == null) {
199: throw new NullPointerException();
200: }
201:
202:• if (base != null && base instanceof List) {
203: context.setPropertyResolved(base, property);
204: // Safe cast
205: @SuppressWarnings("unchecked")
206: List<Object> list = (List<Object>) base;
207: int index = toInteger(property);
208:• if (isReadOnly) {
209: throw new PropertyNotWritableException();
210: }
211:
212: try {
213: list.set(index, val);
214: } catch (UnsupportedOperationException ex) {
215: throw new PropertyNotWritableException();
216: } catch (IndexOutOfBoundsException ex) {
217: throw new PropertyNotFoundException();
218: } catch (ClassCastException ex) {
219: throw ex;
220: } catch (NullPointerException ex) {
221: throw ex;
222: } catch (IllegalArgumentException ex) {
223: throw ex;
224: }
225: }
226: }
227:
228: /**
229: * If the base object is a list, returns whether a call to {@link #setValue} will always fail.
230: *
231: * <p>
232: * If the base is a <code>List</code>, the <code>propertyResolved</code> property of the <code>ELContext</code> object
233: * must be set to <code>true</code> by this resolver, before returning. If this property is not <code>true</code> after
234: * this method is called, the caller should ignore the return value.
235: * </p>
236: *
237: * <p>
238: * If this resolver was constructed in read-only mode, this method will always return <code>true</code>.
239: * </p>
240: *
241: * <p>
242: * If a <code>List</code> was created using {@link java.util.Collections#unmodifiableList}, this method must return
243: * <code>true</code>. Unfortunately, there is no Collections API method to detect this. However, an implementation can
244: * create a prototype unmodifiable <code>List</code> and query its runtime type to see if it matches the runtime type of
245: * the base object as a workaround.
246: * </p>
247: *
248: * @param context The context of this evaluation.
249: * @param base The list to analyze. Only bases of type <code>List</code> are handled by this resolver.
250: * @param property The index of the element in the list to return the acceptable type for. Will be coerced into an
251: * integer, but otherwise ignored by this resolver.
252: * @return If the <code>propertyResolved</code> property of <code>ELContext</code> was set to <code>true</code>, then
253: * <code>true</code> if calling the <code>setValue</code> method will always fail or <code>false</code> if it is
254: * possible that such a call may succeed; otherwise undefined.
255: * @throws PropertyNotFoundException if the given index is out of bounds for this list.
256: * @throws NullPointerException if context is <code>null</code>
257: * @throws ELException if an exception was thrown while performing the property or variable resolution. The thrown
258: * exception must be included as the cause property of this exception, if available.
259: */
260: @Override
261: public boolean isReadOnly(ELContext context, Object base, Object property) {
262:• if (context == null) {
263: throw new NullPointerException();
264: }
265:
266:• if (base != null && base instanceof List) {
267: context.setPropertyResolved(true);
268: List<?> list = (List<?>) base;
269: int index = toInteger(property);
270:• if (index < 0 || index >= list.size()) {
271: throw new PropertyNotFoundException();
272: }
273:
274:• return list.getClass() == theUnmodifiableListClass || isReadOnly;
275: }
276:
277: return false;
278: }
279:
280: /**
281: * Always returns <code>null</code>, since there is no reason to iterate through set set of all integers.
282: *
283: * <p>
284: * The {@link #getCommonPropertyType} method returns sufficient information about what properties this resolver accepts.
285: * </p>
286: *
287: * @param context The context of this evaluation.
288: * @param base The list. Only bases of type <code>List</code> are handled by this resolver.
289: * @return <code>null</code>.
290: *
291: * @deprecated This method will be removed without replacement in EL 6.0
292: */
293: @Deprecated(forRemoval = true, since = "5.0")
294: @Override
295: public Iterator<FeatureDescriptor> getFeatureDescriptors(ELContext context, Object base) {
296: return null;
297: }
298:
299: /**
300: * If the base object is a list, returns the most general type that this resolver accepts for the <code>property</code>
301: * argument. Otherwise, returns <code>null</code>.
302: *
303: * <p>
304: * Assuming the base is a <code>List</code>, this method will always return <code>Integer.class</code>. This is because
305: * <code>List</code>s accept integers as their index.
306: * </p>
307: *
308: * @param context The context of this evaluation.
309: * @param base The list to analyze. Only bases of type <code>List</code> are handled by this resolver.
310: * @return <code>null</code> if base is not a <code>List</code> otherwise <code>Integer.class</code>.
311: */
312: @Override
313: public Class<?> getCommonPropertyType(ELContext context, Object base) {
314:• if (base != null && base instanceof List) {
315: return Integer.class;
316: }
317:
318: return null;
319: }
320:
321: private int toInteger(Object p) {
322:• if (p instanceof Integer) {
323: return ((Integer) p).intValue();
324: }
325:• if (p instanceof Character) {
326: return ((Character) p).charValue();
327: }
328:• if (p instanceof Number) {
329: return ((Number) p).intValue();
330: }
331:• if (p instanceof String) {
332: return Integer.parseInt((String) p);
333: }
334: throw new IllegalArgumentException();
335: }
336: }