Source Code Cross Referenced for BeanMap.java in  » Library » Apache-commons-beanutils-1.8.0-BETA-src » org » apache » commons » beanutils » Java Source Code / Java DocumentationJava Source Code and Java Documentation

Java Source Code / Java Documentation
1. 6.0 JDK Core
2. 6.0 JDK Modules
3. 6.0 JDK Modules com.sun
4. 6.0 JDK Modules com.sun.java
5. 6.0 JDK Modules sun
6. 6.0 JDK Platform
7. Ajax
8. Apache Harmony Java SE
9. Aspect oriented
10. Authentication Authorization
11. Blogger System
12. Build
13. Byte Code
14. Cache
15. Chart
16. Chat
17. Code Analyzer
18. Collaboration
19. Content Management System
20. Database Client
21. Database DBMS
22. Database JDBC Connection Pool
23. Database ORM
24. Development
25. EJB Server geronimo
26. EJB Server GlassFish
27. EJB Server JBoss 4.2.1
28. EJB Server resin 3.1.5
29. ERP CRM Financial
30. ESB
31. Forum
32. GIS
33. Graphic Library
34. Groupware
35. HTML Parser
36. IDE
37. IDE Eclipse
38. IDE Netbeans
39. Installer
40. Internationalization Localization
41. Inversion of Control
42. Issue Tracking
43. J2EE
44. JBoss
45. JMS
46. JMX
47. Library
48. Mail Clients
49. Net
50. Parser
51. PDF
52. Portal
53. Profiler
54. Project Management
55. Report
56. RSS RDF
57. Rule Engine
58. Science
59. Scripting
60. Search Engine
61. Security
62. Sevlet Container
63. Source Control
64. Swing Library
65. Template Engine
66. Test Coverage
67. Testing
68. UML
69. Web Crawler
70. Web Framework
71. Web Mail
72. Web Server
73. Web Services
74. Web Services apache cxf 2.0.1
75. Web Services AXIS2
76. Wiki Engine
77. Workflow Engines
78. XML
79. XML UI
Java
Java Tutorial
Java Open Source
Jar File Download
Java Articles
Java Products
Java by API
Photoshop Tutorials
Maya Tutorials
Flash Tutorials
3ds-Max Tutorials
Illustrator Tutorials
GIMP Tutorials
C# / C Sharp
C# / CSharp Tutorial
C# / CSharp Open Source
ASP.Net
ASP.NET Tutorial
JavaScript DHTML
JavaScript Tutorial
JavaScript Reference
HTML / CSS
HTML CSS Reference
C / ANSI-C
C Tutorial
C++
C++ Tutorial
Ruby
PHP
Python
Python Tutorial
Python Open Source
SQL Server / T-SQL
SQL Server / T-SQL Tutorial
Oracle PL / SQL
Oracle PL/SQL Tutorial
PostgreSQL
SQL / MySQL
MySQL Tutorial
VB.Net
VB.Net Tutorial
Flash / Flex / ActionScript
VBA / Excel / Access / Word
XML
XML Tutorial
Microsoft Office PowerPoint 2007 Tutorial
Microsoft Office Excel 2007 Tutorial
Microsoft Office Word 2007 Tutorial
Java Source Code / Java Documentation » Library » Apache commons beanutils 1.8.0 BETA src » org.apache.commons.beanutils 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


001:        /*
002:         * Licensed to the Apache Software Foundation (ASF) under one or more
003:         * contributor license agreements.  See the NOTICE file distributed with
004:         * this work for additional information regarding copyright ownership.
005:         * The ASF licenses this file to You under the Apache License, Version 2.0
006:         * (the "License"); you may not use this file except in compliance with
007:         * the License.  You may obtain a copy of the License at
008:         *
009:         *      http://www.apache.org/licenses/LICENSE-2.0
010:         *
011:         * Unless required by applicable law or agreed to in writing, software
012:         * distributed under the License is distributed on an "AS IS" BASIS,
013:         * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014:         * See the License for the specific language governing permissions and
015:         * limitations under the License.
016:         */
017:        package org.apache.commons.beanutils;
018:
019:        import java.beans.BeanInfo;
020:        import java.beans.IntrospectionException;
021:        import java.beans.Introspector;
022:        import java.beans.PropertyDescriptor;
023:        import java.lang.reflect.Constructor;
024:        import java.lang.reflect.InvocationTargetException;
025:        import java.lang.reflect.Method;
026:        import java.util.AbstractMap;
027:        import java.util.AbstractSet;
028:        import java.util.ArrayList;
029:        import java.util.Collection;
030:        import java.util.Collections;
031:        import java.util.HashMap;
032:        import java.util.Iterator;
033:        import java.util.Map;
034:        import java.util.Set;
035:
036:        import org.apache.commons.collections.list.UnmodifiableList;
037:        import org.apache.commons.collections.keyvalue.AbstractMapEntry;
038:        import org.apache.commons.collections.set.UnmodifiableSet;
039:        import org.apache.commons.collections.Transformer;
040:
041:        /** 
042:         * An implementation of Map for JavaBeans which uses introspection to
043:         * get and put properties in the bean.
044:         * <p>
045:         * If an exception occurs during attempts to get or set a property then the
046:         * property is considered non existent in the Map
047:         *
048:         * @version $Revision: 557796 $ $Date: 2007-07-19 23:28:49 +0100 (Thu, 19 Jul 2007) $
049:         * 
050:         * @author James Strachan
051:         * @author Stephen Colebourne
052:         */
053:        public class BeanMap extends AbstractMap implements  Cloneable {
054:
055:            private transient Object bean;
056:
057:            private transient HashMap readMethods = new HashMap();
058:            private transient HashMap writeMethods = new HashMap();
059:            private transient HashMap types = new HashMap();
060:
061:            /**
062:             * An empty array.  Used to invoke accessors via reflection.
063:             */
064:            public static final Object[] NULL_ARGUMENTS = {};
065:
066:            /**
067:             * Maps primitive Class types to transformers.  The transformer
068:             * transform strings into the appropriate primitive wrapper.
069:             *
070:             * N.B. private & unmodifiable replacement for the (public & static) defaultTransformers instance.
071:             */
072:            private static Map typeTransformers = Collections
073:                    .unmodifiableMap(createTypeTransformers());
074:
075:            /**
076:             * This HashMap has been made unmodifiable to prevent issues when
077:             * loaded in a shared ClassLoader enviroment.
078:             *
079:             * @see http://issues.apache.org/jira/browse/BEANUTILS-112
080:             * @deprecated Use {@link BeanMap#getTypeTransformer(Class)} method
081:             */
082:            public static HashMap defaultTransformers = new HashMap() {
083:                public void clear() {
084:                    throw new UnsupportedOperationException();
085:                }
086:
087:                public boolean containsKey(Object key) {
088:                    return typeTransformers.containsKey(key);
089:                }
090:
091:                public boolean containsValue(Object value) {
092:                    return typeTransformers.containsValue(value);
093:                }
094:
095:                public Set entrySet() {
096:                    return typeTransformers.entrySet();
097:                }
098:
099:                public Object get(Object key) {
100:                    return typeTransformers.get(key);
101:                }
102:
103:                public boolean isEmpty() {
104:                    return false;
105:                }
106:
107:                public Set keySet() {
108:                    return typeTransformers.keySet();
109:                }
110:
111:                public Object put(Object key, Object value) {
112:                    throw new UnsupportedOperationException();
113:                }
114:
115:                public void putAll(Map m) {
116:                    throw new UnsupportedOperationException();
117:                }
118:
119:                public Object remove(Object key) {
120:                    throw new UnsupportedOperationException();
121:                }
122:
123:                public int size() {
124:                    return typeTransformers.size();
125:                }
126:
127:                public Collection values() {
128:                    return typeTransformers.values();
129:                }
130:            };
131:
132:            private static Map createTypeTransformers() {
133:                Map defaultTransformers = new HashMap();
134:                defaultTransformers.put(Boolean.TYPE, new Transformer() {
135:                    public Object transform(Object input) {
136:                        return Boolean.valueOf(input.toString());
137:                    }
138:                });
139:                defaultTransformers.put(Character.TYPE, new Transformer() {
140:                    public Object transform(Object input) {
141:                        return new Character(input.toString().charAt(0));
142:                    }
143:                });
144:                defaultTransformers.put(Byte.TYPE, new Transformer() {
145:                    public Object transform(Object input) {
146:                        return Byte.valueOf(input.toString());
147:                    }
148:                });
149:                defaultTransformers.put(Short.TYPE, new Transformer() {
150:                    public Object transform(Object input) {
151:                        return Short.valueOf(input.toString());
152:                    }
153:                });
154:                defaultTransformers.put(Integer.TYPE, new Transformer() {
155:                    public Object transform(Object input) {
156:                        return Integer.valueOf(input.toString());
157:                    }
158:                });
159:                defaultTransformers.put(Long.TYPE, new Transformer() {
160:                    public Object transform(Object input) {
161:                        return Long.valueOf(input.toString());
162:                    }
163:                });
164:                defaultTransformers.put(Float.TYPE, new Transformer() {
165:                    public Object transform(Object input) {
166:                        return Float.valueOf(input.toString());
167:                    }
168:                });
169:                defaultTransformers.put(Double.TYPE, new Transformer() {
170:                    public Object transform(Object input) {
171:                        return Double.valueOf(input.toString());
172:                    }
173:                });
174:                return defaultTransformers;
175:            }
176:
177:            // Constructors
178:            //-------------------------------------------------------------------------
179:
180:            /**
181:             * Constructs a new empty <code>BeanMap</code>.
182:             */
183:            public BeanMap() {
184:            }
185:
186:            /**
187:             * Constructs a new <code>BeanMap</code> that operates on the 
188:             * specified bean.  If the given bean is <code>null</code>, then
189:             * this map will be empty.
190:             *
191:             * @param bean  the bean for this map to operate on
192:             */
193:            public BeanMap(Object bean) {
194:                this .bean = bean;
195:                initialise();
196:            }
197:
198:            // Map interface
199:            //-------------------------------------------------------------------------
200:
201:            /**
202:             * Renders a string representation of this object.
203:             * @return a <code>String</code> representation of this object
204:             */
205:            public String toString() {
206:                return "BeanMap<" + String.valueOf(bean) + ">";
207:            }
208:
209:            /**
210:             * Clone this bean map using the following process: 
211:             *
212:             * <ul>
213:             * <li>If there is no underlying bean, return a cloned BeanMap without a
214:             * bean.
215:             *
216:             * <li>Since there is an underlying bean, try to instantiate a new bean of
217:             * the same type using Class.newInstance().
218:             * 
219:             * <li>If the instantiation fails, throw a CloneNotSupportedException
220:             *
221:             * <li>Clone the bean map and set the newly instantiated bean as the
222:             * underlying bean for the bean map.
223:             *
224:             * <li>Copy each property that is both readable and writable from the
225:             * existing object to a cloned bean map.  
226:             *
227:             * <li>If anything fails along the way, throw a
228:             * CloneNotSupportedException.
229:             *
230:             * <ul>
231:             *
232:             * @return a cloned instance of this bean map
233:             * @throws CloneNotSupportedException if the underlying bean
234:             * cannot be cloned
235:             */
236:            public Object clone() throws CloneNotSupportedException {
237:                BeanMap newMap = (BeanMap) super .clone();
238:
239:                if (bean == null) {
240:                    // no bean, just an empty bean map at the moment.  return a newly
241:                    // cloned and empty bean map.
242:                    return newMap;
243:                }
244:
245:                Object newBean = null;
246:                Class beanClass = null;
247:                try {
248:                    beanClass = bean.getClass();
249:                    newBean = beanClass.newInstance();
250:                } catch (Exception e) {
251:                    // unable to instantiate
252:                    throw new CloneNotSupportedException(
253:                            "Unable to instantiate the underlying bean \""
254:                                    + beanClass.getName() + "\": " + e);
255:                }
256:
257:                try {
258:                    newMap.setBean(newBean);
259:                } catch (Exception exception) {
260:                    throw new CloneNotSupportedException(
261:                            "Unable to set bean in the cloned bean map: "
262:                                    + exception);
263:                }
264:
265:                try {
266:                    // copy only properties that are readable and writable.  If its
267:                    // not readable, we can't get the value from the old map.  If
268:                    // its not writable, we can't write a value into the new map.
269:                    Iterator readableKeys = readMethods.keySet().iterator();
270:                    while (readableKeys.hasNext()) {
271:                        Object key = readableKeys.next();
272:                        if (getWriteMethod(key) != null) {
273:                            newMap.put(key, get(key));
274:                        }
275:                    }
276:                } catch (Exception exception) {
277:                    throw new CloneNotSupportedException(
278:                            "Unable to copy bean values to cloned bean map: "
279:                                    + exception);
280:                }
281:
282:                return newMap;
283:            }
284:
285:            /**
286:             * Puts all of the writable properties from the given BeanMap into this
287:             * BeanMap. Read-only and Write-only properties will be ignored.
288:             *
289:             * @param map  the BeanMap whose properties to put
290:             */
291:            public void putAllWriteable(BeanMap map) {
292:                Iterator readableKeys = map.readMethods.keySet().iterator();
293:                while (readableKeys.hasNext()) {
294:                    Object key = readableKeys.next();
295:                    if (getWriteMethod(key) != null) {
296:                        this .put(key, map.get(key));
297:                    }
298:                }
299:            }
300:
301:            /**
302:             * This method reinitializes the bean map to have default values for the
303:             * bean's properties.  This is accomplished by constructing a new instance
304:             * of the bean which the map uses as its underlying data source.  This
305:             * behavior for <code>clear()</code> differs from the Map contract in that
306:             * the mappings are not actually removed from the map (the mappings for a
307:             * BeanMap are fixed).
308:             */
309:            public void clear() {
310:                if (bean == null) {
311:                    return;
312:                }
313:
314:                Class beanClass = null;
315:                try {
316:                    beanClass = bean.getClass();
317:                    bean = beanClass.newInstance();
318:                } catch (Exception e) {
319:                    throw new UnsupportedOperationException(
320:                            "Could not create new instance of class: "
321:                                    + beanClass);
322:                }
323:            }
324:
325:            /**
326:             * Returns true if the bean defines a property with the given name.
327:             * <p>
328:             * The given name must be a <code>String</code>; if not, this method
329:             * returns false. This method will also return false if the bean
330:             * does not define a property with that name.
331:             * <p>
332:             * Write-only properties will not be matched as the test operates against
333:             * property read methods.
334:             *
335:             * @param name  the name of the property to check
336:             * @return false if the given name is null or is not a <code>String</code>;
337:             *   false if the bean does not define a property with that name; or
338:             *   true if the bean does define a property with that name
339:             */
340:            public boolean containsKey(Object name) {
341:                Method method = getReadMethod(name);
342:                return method != null;
343:            }
344:
345:            /**
346:             * Returns true if the bean defines a property whose current value is
347:             * the given object.
348:             *
349:             * @param value  the value to check
350:             * @return false  true if the bean has at least one property whose 
351:             *   current value is that object, false otherwise
352:             */
353:            public boolean containsValue(Object value) {
354:                // use default implementation
355:                return super .containsValue(value);
356:            }
357:
358:            /**
359:             * Returns the value of the bean's property with the given name.
360:             * <p>
361:             * The given name must be a {@link String} and must not be 
362:             * null; otherwise, this method returns <code>null</code>.
363:             * If the bean defines a property with the given name, the value of
364:             * that property is returned.  Otherwise, <code>null</code> is 
365:             * returned.
366:             * <p>
367:             * Write-only properties will not be matched as the test operates against
368:             * property read methods.
369:             *
370:             * @param name  the name of the property whose value to return
371:             * @return  the value of the property with that name
372:             */
373:            public Object get(Object name) {
374:                if (bean != null) {
375:                    Method method = getReadMethod(name);
376:                    if (method != null) {
377:                        try {
378:                            return method.invoke(bean, NULL_ARGUMENTS);
379:                        } catch (IllegalAccessException e) {
380:                            logWarn(e);
381:                        } catch (IllegalArgumentException e) {
382:                            logWarn(e);
383:                        } catch (InvocationTargetException e) {
384:                            logWarn(e);
385:                        } catch (NullPointerException e) {
386:                            logWarn(e);
387:                        }
388:                    }
389:                }
390:                return null;
391:            }
392:
393:            /**
394:             * Sets the bean property with the given name to the given value.
395:             *
396:             * @param name  the name of the property to set
397:             * @param value  the value to set that property to
398:             * @return  the previous value of that property
399:             * @throws IllegalArgumentException  if the given name is null;
400:             *   if the given name is not a {@link String}; if the bean doesn't
401:             *   define a property with that name; or if the bean property with
402:             *   that name is read-only
403:             * @throws ClassCastException if an error occurs creating the method args
404:             */
405:            public Object put(Object name, Object value)
406:                    throws IllegalArgumentException, ClassCastException {
407:                if (bean != null) {
408:                    Object oldValue = get(name);
409:                    Method method = getWriteMethod(name);
410:                    if (method == null) {
411:                        throw new IllegalArgumentException("The bean of type: "
412:                                + bean.getClass().getName()
413:                                + " has no property called: " + name);
414:                    }
415:                    try {
416:                        Object[] arguments = createWriteMethodArguments(method,
417:                                value);
418:                        method.invoke(bean, arguments);
419:
420:                        Object newValue = get(name);
421:                        firePropertyChange(name, oldValue, newValue);
422:                    } catch (InvocationTargetException e) {
423:                        logInfo(e);
424:                        throw new IllegalArgumentException(e.getMessage());
425:                    } catch (IllegalAccessException e) {
426:                        logInfo(e);
427:                        throw new IllegalArgumentException(e.getMessage());
428:                    }
429:                    return oldValue;
430:                }
431:                return null;
432:            }
433:
434:            /**
435:             * Returns the number of properties defined by the bean.
436:             *
437:             * @return  the number of properties defined by the bean
438:             */
439:            public int size() {
440:                return readMethods.size();
441:            }
442:
443:            /**
444:             * Get the keys for this BeanMap.
445:             * <p>
446:             * Write-only properties are <b>not</b> included in the returned set of
447:             * property names, although it is possible to set their value and to get 
448:             * their type.
449:             * 
450:             * @return BeanMap keys.  The Set returned by this method is not
451:             *        modifiable.
452:             */
453:            public Set keySet() {
454:                return UnmodifiableSet.decorate(readMethods.keySet());
455:            }
456:
457:            /**
458:             * Gets a Set of MapEntry objects that are the mappings for this BeanMap.
459:             * <p>
460:             * Each MapEntry can be set but not removed.
461:             * 
462:             * @return the unmodifiable set of mappings
463:             */
464:            public Set entrySet() {
465:                return UnmodifiableSet.decorate(new AbstractSet() {
466:                    public Iterator iterator() {
467:                        return entryIterator();
468:                    }
469:
470:                    public int size() {
471:                        return BeanMap.this .readMethods.size();
472:                    }
473:                });
474:            }
475:
476:            /**
477:             * Returns the values for the BeanMap.
478:             * 
479:             * @return values for the BeanMap.  The returned collection is not
480:             *        modifiable.
481:             */
482:            public Collection values() {
483:                ArrayList answer = new ArrayList(readMethods.size());
484:                for (Iterator iter = valueIterator(); iter.hasNext();) {
485:                    answer.add(iter.next());
486:                }
487:                return UnmodifiableList.decorate(answer);
488:            }
489:
490:            // Helper methods
491:            //-------------------------------------------------------------------------
492:
493:            /**
494:             * Returns the type of the property with the given name.
495:             *
496:             * @param name  the name of the property
497:             * @return  the type of the property, or <code>null</code> if no such
498:             *  property exists
499:             */
500:            public Class getType(String name) {
501:                return (Class) types.get(name);
502:            }
503:
504:            /**
505:             * Convenience method for getting an iterator over the keys.
506:             * <p>
507:             * Write-only properties will not be returned in the iterator.
508:             *
509:             * @return an iterator over the keys
510:             */
511:            public Iterator keyIterator() {
512:                return readMethods.keySet().iterator();
513:            }
514:
515:            /**
516:             * Convenience method for getting an iterator over the values.
517:             *
518:             * @return an iterator over the values
519:             */
520:            public Iterator valueIterator() {
521:                final Iterator iter = keyIterator();
522:                return new Iterator() {
523:                    public boolean hasNext() {
524:                        return iter.hasNext();
525:                    }
526:
527:                    public Object next() {
528:                        Object key = iter.next();
529:                        return get(key);
530:                    }
531:
532:                    public void remove() {
533:                        throw new UnsupportedOperationException(
534:                                "remove() not supported for BeanMap");
535:                    }
536:                };
537:            }
538:
539:            /**
540:             * Convenience method for getting an iterator over the entries.
541:             *
542:             * @return an iterator over the entries
543:             */
544:            public Iterator entryIterator() {
545:                final Iterator iter = keyIterator();
546:                return new Iterator() {
547:                    public boolean hasNext() {
548:                        return iter.hasNext();
549:                    }
550:
551:                    public Object next() {
552:                        Object key = iter.next();
553:                        Object value = get(key);
554:                        return new Entry(BeanMap.this , key, value);
555:                    }
556:
557:                    public void remove() {
558:                        throw new UnsupportedOperationException(
559:                                "remove() not supported for BeanMap");
560:                    }
561:                };
562:            }
563:
564:            // Properties
565:            //-------------------------------------------------------------------------
566:
567:            /**
568:             * Returns the bean currently being operated on.  The return value may
569:             * be null if this map is empty.
570:             *
571:             * @return the bean being operated on by this map
572:             */
573:            public Object getBean() {
574:                return bean;
575:            }
576:
577:            /**
578:             * Sets the bean to be operated on by this map.  The given value may
579:             * be null, in which case this map will be empty.
580:             *
581:             * @param newBean  the new bean to operate on
582:             */
583:            public void setBean(Object newBean) {
584:                bean = newBean;
585:                reinitialise();
586:            }
587:
588:            /**
589:             * Returns the accessor for the property with the given name.
590:             *
591:             * @param name  the name of the property 
592:             * @return the accessor method for the property, or null
593:             */
594:            public Method getReadMethod(String name) {
595:                return (Method) readMethods.get(name);
596:            }
597:
598:            /**
599:             * Returns the mutator for the property with the given name.
600:             *
601:             * @param name  the name of the property
602:             * @return the mutator method for the property, or null
603:             */
604:            public Method getWriteMethod(String name) {
605:                return (Method) writeMethods.get(name);
606:            }
607:
608:            // Implementation methods
609:            //-------------------------------------------------------------------------
610:
611:            /**
612:             * Returns the accessor for the property with the given name.
613:             *
614:             * @param name  the name of the property 
615:             * @return null if the name is null; null if the name is not a 
616:             * {@link String}; null if no such property exists; or the accessor
617:             *  method for that property
618:             */
619:            protected Method getReadMethod(Object name) {
620:                return (Method) readMethods.get(name);
621:            }
622:
623:            /**
624:             * Returns the mutator for the property with the given name.
625:             *
626:             * @param name  the name of the 
627:             * @return null if the name is null; null if the name is not a 
628:             * {@link String}; null if no such property exists; null if the 
629:             * property is read-only; or the mutator method for that property
630:             */
631:            protected Method getWriteMethod(Object name) {
632:                return (Method) writeMethods.get(name);
633:            }
634:
635:            /**
636:             * Reinitializes this bean.  Called during {@link #setBean(Object)}.
637:             * Does introspection to find properties.
638:             */
639:            protected void reinitialise() {
640:                readMethods.clear();
641:                writeMethods.clear();
642:                types.clear();
643:                initialise();
644:            }
645:
646:            private void initialise() {
647:                if (getBean() == null) {
648:                    return;
649:                }
650:
651:                Class beanClass = getBean().getClass();
652:                try {
653:                    //BeanInfo beanInfo = Introspector.getBeanInfo( bean, null );
654:                    BeanInfo beanInfo = Introspector.getBeanInfo(beanClass);
655:                    PropertyDescriptor[] propertyDescriptors = beanInfo
656:                            .getPropertyDescriptors();
657:                    if (propertyDescriptors != null) {
658:                        for (int i = 0; i < propertyDescriptors.length; i++) {
659:                            PropertyDescriptor propertyDescriptor = propertyDescriptors[i];
660:                            if (propertyDescriptor != null) {
661:                                String name = propertyDescriptor.getName();
662:                                Method readMethod = propertyDescriptor
663:                                        .getReadMethod();
664:                                Method writeMethod = propertyDescriptor
665:                                        .getWriteMethod();
666:                                Class aType = propertyDescriptor
667:                                        .getPropertyType();
668:
669:                                if (readMethod != null) {
670:                                    readMethods.put(name, readMethod);
671:                                }
672:                                if (writeMethod != null) {
673:                                    writeMethods.put(name, writeMethod);
674:                                }
675:                                types.put(name, aType);
676:                            }
677:                        }
678:                    }
679:                } catch (IntrospectionException e) {
680:                    logWarn(e);
681:                }
682:            }
683:
684:            /**
685:             * Called during a successful {@link #put(Object,Object)} operation.
686:             * Default implementation does nothing.  Override to be notified of
687:             * property changes in the bean caused by this map.
688:             *
689:             * @param key  the name of the property that changed
690:             * @param oldValue  the old value for that property
691:             * @param newValue  the new value for that property
692:             */
693:            protected void firePropertyChange(Object key, Object oldValue,
694:                    Object newValue) {
695:            }
696:
697:            // Implementation classes
698:            //-------------------------------------------------------------------------
699:
700:            /**
701:             * Map entry used by {@link BeanMap}.
702:             */
703:            protected static class Entry extends AbstractMapEntry {
704:                private BeanMap owner;
705:
706:                /**
707:                 * Constructs a new <code>Entry</code>.
708:                 *
709:                 * @param owner  the BeanMap this entry belongs to
710:                 * @param key  the key for this entry
711:                 * @param value  the value for this entry
712:                 */
713:                protected Entry(BeanMap owner, Object key, Object value) {
714:                    super (key, value);
715:                    this .owner = owner;
716:                }
717:
718:                /**
719:                 * Sets the value.
720:                 *
721:                 * @param value  the new value for the entry
722:                 * @return the old value for the entry
723:                 */
724:                public Object setValue(Object value) {
725:                    Object key = getKey();
726:                    Object oldValue = owner.get(key);
727:
728:                    owner.put(key, value);
729:                    Object newValue = owner.get(key);
730:                    super .setValue(newValue);
731:                    return oldValue;
732:                }
733:            }
734:
735:            /**
736:             * Creates an array of parameters to pass to the given mutator method.
737:             * If the given object is not the right type to pass to the method 
738:             * directly, it will be converted using {@link #convertType(Class,Object)}.
739:             *
740:             * @param method  the mutator method
741:             * @param value  the value to pass to the mutator method
742:             * @return an array containing one object that is either the given value
743:             *   or a transformed value
744:             * @throws IllegalAccessException if {@link #convertType(Class,Object)}
745:             *   raises it
746:             * @throws IllegalArgumentException if any other exception is raised
747:             *   by {@link #convertType(Class,Object)}
748:             * @throws ClassCastException if an error occurs creating the method args
749:             */
750:            protected Object[] createWriteMethodArguments(Method method,
751:                    Object value) throws IllegalAccessException,
752:                    ClassCastException {
753:                try {
754:                    if (value != null) {
755:                        Class[] types = method.getParameterTypes();
756:                        if (types != null && types.length > 0) {
757:                            Class paramType = types[0];
758:                            if (!paramType.isAssignableFrom(value.getClass())) {
759:                                value = convertType(paramType, value);
760:                            }
761:                        }
762:                    }
763:                    Object[] answer = { value };
764:                    return answer;
765:                } catch (InvocationTargetException e) {
766:                    logInfo(e);
767:                    throw new IllegalArgumentException(e.getMessage());
768:                } catch (InstantiationException e) {
769:                    logInfo(e);
770:                    throw new IllegalArgumentException(e.getMessage());
771:                }
772:            }
773:
774:            /**
775:             * Converts the given value to the given type.  First, reflection is
776:             * is used to find a public constructor declared by the given class 
777:             * that takes one argument, which must be the precise type of the 
778:             * given value.  If such a constructor is found, a new object is
779:             * created by passing the given value to that constructor, and the
780:             * newly constructed object is returned.<P>
781:             *
782:             * If no such constructor exists, and the given type is a primitive
783:             * type, then the given value is converted to a string using its 
784:             * {@link Object#toString() toString()} method, and that string is
785:             * parsed into the correct primitive type using, for instance, 
786:             * {@link Integer#valueOf(String)} to convert the string into an
787:             * <code>int</code>.<P>
788:             *
789:             * If no special constructor exists and the given type is not a 
790:             * primitive type, this method returns the original value.
791:             *
792:             * @param newType  the type to convert the value to
793:             * @param value  the value to convert
794:             * @return the converted value
795:             * @throws NumberFormatException if newType is a primitive type, and 
796:             *  the string representation of the given value cannot be converted
797:             *  to that type
798:             * @throws InstantiationException  if the constructor found with 
799:             *  reflection raises it
800:             * @throws InvocationTargetException  if the constructor found with
801:             *  reflection raises it
802:             * @throws IllegalAccessException  never
803:             * @throws IllegalArgumentException  never
804:             */
805:            protected Object convertType(Class newType, Object value)
806:                    throws InstantiationException, IllegalAccessException,
807:                    IllegalArgumentException, InvocationTargetException {
808:
809:                // try call constructor
810:                Class[] types = { value.getClass() };
811:                try {
812:                    Constructor constructor = newType.getConstructor(types);
813:                    Object[] arguments = { value };
814:                    return constructor.newInstance(arguments);
815:                } catch (NoSuchMethodException e) {
816:                    // try using the transformers
817:                    Transformer transformer = getTypeTransformer(newType);
818:                    if (transformer != null) {
819:                        return transformer.transform(value);
820:                    }
821:                    return value;
822:                }
823:            }
824:
825:            /**
826:             * Returns a transformer for the given primitive type.
827:             *
828:             * @param aType  the primitive type whose transformer to return
829:             * @return a transformer that will convert strings into that type,
830:             *  or null if the given type is not a primitive type
831:             */
832:            protected Transformer getTypeTransformer(Class aType) {
833:                return (Transformer) typeTransformers.get(aType);
834:            }
835:
836:            /**
837:             * Logs the given exception to <code>System.out</code>.  Used to display
838:             * warnings while accessing/mutating the bean.
839:             *
840:             * @param ex  the exception to log
841:             */
842:            protected void logInfo(Exception ex) {
843:                // Deliberately do not use LOG4J or Commons Logging to avoid dependencies
844:                System.out.println("INFO: Exception: " + ex);
845:            }
846:
847:            /**
848:             * Logs the given exception to <code>System.err</code>.  Used to display
849:             * errors while accessing/mutating the bean.
850:             *
851:             * @param ex  the exception to log
852:             */
853:            protected void logWarn(Exception ex) {
854:                // Deliberately do not use LOG4J or Commons Logging to avoid dependencies
855:                System.out.println("WARN: Exception: " + ex);
856:                ex.printStackTrace();
857:            }
858:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.