001: /*
002: * Copyright 2004-2007 the original author or authors.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016: package org.springframework.binding.collection;
017:
018: import java.util.Collection;
019: import java.util.Map;
020:
021: import org.springframework.util.Assert;
022:
023: /**
024: * A simple, generic decorator for getting attributes out of a map. May be
025: * instantiated directly or used as a base class as a convenience.
026: *
027: * @author Keith Donald
028: */
029: public class MapAccessor implements MapAdaptable {
030:
031: /**
032: * The target map.
033: */
034: private Map map;
035:
036: /**
037: * Creates a new attribute map accessor.
038: * @param map the map
039: */
040: public MapAccessor(Map map) {
041: Assert.notNull(map, "The map to decorate is required");
042: this .map = map;
043: }
044:
045: // implementing MapAdaptable
046:
047: public Map asMap() {
048: return map;
049: }
050:
051: /**
052: * Returns a value in the map, returning the defaultValue if no value was
053: * found.
054: * @param key the key
055: * @param defaultValue the default
056: * @return the attribute value
057: */
058: public Object get(Object key, Object defaultValue) {
059: if (!map.containsKey(key)) {
060: return defaultValue;
061: }
062: return map.get(key);
063: }
064:
065: /**
066: * Returns a value in the map, asserting it is of the required type if
067: * present and returning <code>null</code> if not found.
068: * @param key the key
069: * @param requiredType the required type
070: * @return the value
071: * @throws IllegalArgumentException if the key is present but the value is
072: * not of the required type
073: */
074: public Object get(Object key, Class requiredType)
075: throws IllegalArgumentException {
076: return get(key, requiredType, null);
077: }
078:
079: /**
080: * Returns a value in the map of the specified type, returning the
081: * defaultValue if no value is found.
082: * @param key the key
083: * @param requiredType the required type
084: * @param defaultValue the default
085: * @return the attribute value
086: * @throws IllegalArgumentException if the key is present but the value is
087: * not of the required type
088: */
089: public Object get(Object key, Class requiredType,
090: Object defaultValue) {
091: if (!map.containsKey(key)) {
092: return defaultValue;
093: }
094: return assertKeyValueOfType(key, requiredType);
095: }
096:
097: /**
098: * Returns a value in the map, throwing an exception if the attribute is not
099: * present and of the correct type.
100: * @param key the key
101: * @return the value
102: */
103: public Object getRequired(Object key)
104: throws IllegalArgumentException {
105: assertContainsKey(key);
106: return map.get(key);
107: }
108:
109: /**
110: * Returns an value in the map, asserting it is present and of the required
111: * type.
112: * @param key the key
113: * @param requiredType the required type
114: * @return the value
115: */
116: public Object getRequired(Object key, Class requiredType)
117: throws IllegalArgumentException {
118: assertContainsKey(key);
119: return assertKeyValueOfType(key, requiredType);
120: }
121:
122: /**
123: * Returns a string value in the map, returning <code>null</code> if no
124: * value was found.
125: * @param key the key
126: * @return the string value
127: * @throws IllegalArgumentException if the key is present but the value is
128: * not a string
129: */
130: public String getString(Object key) throws IllegalArgumentException {
131: return getString(key, null);
132: }
133:
134: /**
135: * Returns a string value in the map, returning the defaultValue if no value
136: * was found.
137: * @param key the key
138: * @param defaultValue the default
139: * @return the string value
140: * @throws IllegalArgumentException if the key is present but the value is
141: * not a string
142: */
143: public String getString(Object key, String defaultValue)
144: throws IllegalArgumentException {
145: if (!map.containsKey(key)) {
146: return defaultValue;
147: }
148: return (String) assertKeyValueOfType(key, String.class);
149: }
150:
151: /**
152: * Returns a string value in the map, throwing an exception if the attribute
153: * is not present and of the correct type.
154: * @param key the key
155: * @return the string value
156: * @throws IllegalArgumentException if the key is not present or present but
157: * the value is not a string
158: */
159: public String getRequiredString(Object key)
160: throws IllegalArgumentException {
161: assertContainsKey(key);
162: return (String) assertKeyValueOfType(key, String.class);
163: }
164:
165: /**
166: * Returns a collection value in the map, returning <code>null</code> if
167: * no value was found.
168: * @param key the key
169: * @return the collection value
170: * @throws IllegalArgumentException if the key is present but the value is
171: * not a collection
172: */
173: public Collection getCollection(Object key)
174: throws IllegalArgumentException {
175: if (!map.containsKey(key)) {
176: return null;
177: }
178: return (Collection) assertKeyValueOfType(key, Collection.class);
179: }
180:
181: /**
182: * Returns a collection value in the map, asserting it is of the required
183: * type if present and returning <code>null</code> if not found.
184: * @param key the key
185: * @return the collection value
186: * @throws IllegalArgumentException if the key is present but the value is
187: * not a collection
188: */
189: public Collection getCollection(Object key, Class requiredType)
190: throws IllegalArgumentException {
191: if (!map.containsKey(key)) {
192: return null;
193: }
194: assertAssignableTo(Collection.class, requiredType);
195: return (Collection) assertKeyValueOfType(key, requiredType);
196: }
197:
198: /**
199: * Returns a collection value in the map, throwing an exception if not
200: * found.
201: * @param key the key
202: * @return the collection value
203: * @throws IllegalArgumentException if the key is not present or present but
204: * the value is not a collection
205: */
206: public Collection getRequiredCollection(Object key)
207: throws IllegalArgumentException {
208: assertContainsKey(key);
209: return (Collection) assertKeyValueOfType(key, Collection.class);
210: }
211:
212: /**
213: * Returns a collection value in the map, asserting it is of the required
214: * type if present and throwing an exception if not found.
215: * @param key the key
216: * @return the collection value
217: * @throws IllegalArgumentException if the key is not present or present but
218: * the value is not a collection of the required type
219: */
220: public Collection getRequiredCollection(Object key,
221: Class requiredType) throws IllegalArgumentException {
222: assertContainsKey(key);
223: assertAssignableTo(Collection.class, requiredType);
224: return (Collection) assertKeyValueOfType(key, requiredType);
225: }
226:
227: /**
228: * Returns a array value in the map, asserting it is of the required type if
229: * present and returning <code>null</code> if not found.
230: * @param key the key
231: * @return the array value
232: * @throws IllegalArgumentException if the key is present but the value is
233: * not an array of the required type
234: */
235: public Object[] getArray(Object key, Class requiredType)
236: throws IllegalArgumentException {
237: assertAssignableTo(Object[].class, requiredType);
238: if (!map.containsKey(key)) {
239: return null;
240: }
241: return (Object[]) assertKeyValueOfType(key, requiredType);
242: }
243:
244: /**
245: * Returns an array value in the map, asserting it is of the required type
246: * if present and throwing an exception if not found.
247: * @param key the key
248: * @return the array value
249: * @throws IllegalArgumentException if the key is not present or present but
250: * the value is not a array of the required type
251: */
252: public Object[] getRequiredArray(Object key, Class requiredType)
253: throws IllegalArgumentException {
254: assertContainsKey(key);
255: assertAssignableTo(Object[].class, requiredType);
256: return (Object[]) assertKeyValueOfType(key, requiredType);
257: }
258:
259: /**
260: * Returns a number value in the map that is of the specified type,
261: * returning <code>null</code> if no value was found.
262: * @param key the key
263: * @param requiredType the required number type
264: * @return the numbervalue
265: * @throws IllegalArgumentException if the key is present but the value is
266: * not a number of the required type
267: */
268: public Number getNumber(Object key, Class requiredType)
269: throws IllegalArgumentException {
270: return getNumber(key, requiredType, null);
271: }
272:
273: /**
274: * Returns a number attribute value in the map of the specified type,
275: * returning the defaultValue if no value was found.
276: * @param key the attribute name
277: * @return the number value
278: * @param defaultValue the default
279: * @throws IllegalArgumentException if the key is present but the value is
280: * not a number of the required type
281: */
282: public Number getNumber(Object key, Class requiredType,
283: Number defaultValue) throws IllegalArgumentException {
284: if (!map.containsKey(key)) {
285: return defaultValue;
286: }
287: assertAssignableTo(Number.class, requiredType);
288: return (Number) assertKeyValueOfType(key, requiredType);
289: }
290:
291: /**
292: * Returns a number value in the map, throwing an exception if the attribute
293: * is not present and of the correct type.
294: * @param key the key
295: * @return the number value
296: * @throws IllegalArgumentException if the key is not present or present but
297: * the value is not a number of the required type
298: */
299: public Number getRequiredNumber(Object key, Class requiredType)
300: throws IllegalArgumentException {
301: assertContainsKey(key);
302: return (Number) assertKeyValueOfType(key, requiredType);
303: }
304:
305: /**
306: * Returns an integer value in the map, returning <code>null</code> if no
307: * value was found.
308: * @param key the key
309: * @return the integer value
310: * @throws IllegalArgumentException if the key is present but the value is
311: * not an integer
312: */
313: public Integer getInteger(Object key)
314: throws IllegalArgumentException {
315: return getInteger(key, null);
316: }
317:
318: /**
319: * Returns an integer value in the map, returning the defaultValue if no
320: * value was found.
321: * @param key the key
322: * @param defaultValue the default
323: * @return the integer value
324: * @throws IllegalArgumentException if the key is present but the value is
325: * not an integer
326: */
327: public Integer getInteger(Object key, Integer defaultValue)
328: throws IllegalArgumentException {
329: return (Integer) getNumber(key, Integer.class, defaultValue);
330: }
331:
332: /**
333: * Returns an integer value in the map, throwing an exception if the value
334: * is not present and of the correct type.
335: * @param key the attribute name
336: * @return the integer attribute value
337: * @throws IllegalArgumentException if the key is not present or present but
338: * the value is not an integer
339: */
340: public Integer getRequiredInteger(Object key)
341: throws IllegalArgumentException {
342: return (Integer) getRequiredNumber(key, Integer.class);
343: }
344:
345: /**
346: * Returns a long value in the map, returning <code>null</code> if no
347: * value was found.
348: * @param key the key
349: * @return the long value
350: * @throws IllegalArgumentException if the key is present but not a long
351: */
352: public Long getLong(Object key) throws IllegalArgumentException {
353: return getLong(key, null);
354: }
355:
356: /**
357: * Returns a long value in the map, returning the defaultValue if no value
358: * was found.
359: * @param key the key
360: * @param defaultValue the default
361: * @return the long attribute value
362: * @throws IllegalArgumentException if the key is present but the value is
363: * not a long
364: */
365: public Long getLong(Object key, Long defaultValue)
366: throws IllegalArgumentException {
367: return (Long) getNumber(key, Long.class, defaultValue);
368: }
369:
370: /**
371: * Returns a long value in the map, throwing an exception if the value is
372: * not present and of the correct type.
373: * @param key the key
374: * @return the long attribute value
375: * @throws IllegalArgumentException if the key is not present or present but
376: * the value is not a long
377: */
378: public Long getRequiredLong(Object key)
379: throws IllegalArgumentException {
380: return (Long) getRequiredNumber(key, Long.class);
381: }
382:
383: /**
384: * Returns a boolean value in the map, returning <code>null</code> if no
385: * value was found.
386: * @param key the key
387: * @return the boolean value
388: * @throws IllegalArgumentException if the key is present but the value is
389: * not a boolean
390: */
391: public Boolean getBoolean(Object key)
392: throws IllegalArgumentException {
393: return getBoolean(key, null);
394: }
395:
396: /**
397: * Returns a boolean value in the map, returning the defaultValue if no
398: * value was found.
399: * @param key the key
400: * @param defaultValue the default
401: * @return the boolean value
402: * @throws IllegalArgumentException if the key is present but the value is
403: * not a boolean
404: */
405: public Boolean getBoolean(Object key, Boolean defaultValue)
406: throws IllegalArgumentException {
407: if (!map.containsKey(key)) {
408: return defaultValue;
409: }
410: return (Boolean) assertKeyValueOfType(key, Boolean.class);
411: }
412:
413: /**
414: * Returns a boolean value in the map, throwing an exception if the value is
415: * not present and of the correct type.
416: * @param key the attribute
417: * @return the boolean value
418: * @throws IllegalArgumentException if the key is not present or present but
419: * the value is not a boolean
420: */
421: public Boolean getRequiredBoolean(Object key)
422: throws IllegalArgumentException {
423: assertContainsKey(key);
424: return (Boolean) assertKeyValueOfType(key, Boolean.class);
425: }
426:
427: /**
428: * Asserts that the attribute is present in the attribute map.
429: * @param key the key
430: * @throws IllegalArgumentException if the key is not present
431: */
432: public void assertContainsKey(Object key)
433: throws IllegalArgumentException {
434: if (!map.containsKey(key)) {
435: throw new IllegalArgumentException(
436: "Required attribute '"
437: + key
438: + "' is not present in map; attributes present are ["
439: + asMap() + "]");
440: }
441: }
442:
443: /**
444: * Indicates if the attribute is present in the attribute map and of the
445: * required type.
446: * @param key the attribute name
447: * @return true if present and of the required type, false if not present.
448: */
449: public boolean containsKey(Object key, Class requiredType)
450: throws IllegalArgumentException {
451: if (map.containsKey(key)) {
452: assertKeyValueOfType(key, requiredType);
453: return true;
454: } else {
455: return false;
456: }
457: }
458:
459: /**
460: * Assert that value of the mak key is of the required type.
461: * @param key the attribute name
462: * @param requiredType the required attribute value type
463: * @return the attribute value
464: */
465: public Object assertKeyValueOfType(Object key, Class requiredType) {
466: return assertKeyValueInstanceOf(key, map.get(key), requiredType);
467: }
468:
469: /**
470: * Assert that the key value is an instance of the required type.
471: * @param key the key
472: * @param value the value
473: * @param requiredType the required type
474: * @return the value
475: */
476: public Object assertKeyValueInstanceOf(Object key, Object value,
477: Class requiredType) {
478: Assert.notNull(requiredType,
479: "The required type to assert is required");
480: if (!requiredType.isInstance(value)) {
481: throw new IllegalArgumentException("Map key '"
482: + key
483: + "' has value ["
484: + value
485: + "] that is not of expected type ["
486: + requiredType
487: + "], instead it is of type ["
488: + (value != null ? value.getClass().getName()
489: : "null") + "]");
490: }
491: return value;
492: }
493:
494: private void assertAssignableTo(Class clazz, Class requiredType) {
495: Assert.isTrue(clazz.isAssignableFrom(requiredType),
496: "The provided required type must be assignable to ["
497: + clazz + "]");
498: }
499: }
|