Source Code Cross Referenced for XMLIntrospector.java in  » Library » Apache-commons-betwixt-0.8-src » org » apache » commons » betwixt » 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 betwixt 0.8 src » org.apache.commons.betwixt 
Source Cross Referenced  Class Diagram Java Document (Java Doc) 


0001:        package org.apache.commons.betwixt;
0002:
0003:        /*
0004:         * Licensed to the Apache Software Foundation (ASF) under one or more
0005:         * contributor license agreements.  See the NOTICE file distributed with
0006:         * this work for additional information regarding copyright ownership.
0007:         * The ASF licenses this file to You under the Apache License, Version 2.0
0008:         * (the "License"); you may not use this file except in compliance with
0009:         * the License.  You may obtain a copy of the License at
0010:         * 
0011:         *      http://www.apache.org/licenses/LICENSE-2.0
0012:         * 
0013:         * Unless required by applicable law or agreed to in writing, software
0014:         * distributed under the License is distributed on an "AS IS" BASIS,
0015:         * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
0016:         * See the License for the specific language governing permissions and
0017:         * limitations under the License.
0018:         */
0019:
0020:        import java.beans.BeanDescriptor;
0021:        import java.beans.BeanInfo;
0022:        import java.beans.IntrospectionException;
0023:        import java.beans.Introspector;
0024:        import java.beans.PropertyDescriptor;
0025:        import java.io.IOException;
0026:        import java.lang.reflect.Method;
0027:        import java.net.URL;
0028:        import java.util.ArrayList;
0029:        import java.util.HashMap;
0030:        import java.util.Iterator;
0031:        import java.util.List;
0032:        import java.util.Map;
0033:        import java.util.Set;
0034:
0035:        import org.apache.commons.beanutils.DynaBean;
0036:        import org.apache.commons.beanutils.DynaClass;
0037:        import org.apache.commons.beanutils.DynaProperty;
0038:        import org.apache.commons.betwixt.digester.MultiMappingBeanInfoDigester;
0039:        import org.apache.commons.betwixt.digester.XMLBeanInfoDigester;
0040:        import org.apache.commons.betwixt.digester.XMLIntrospectorHelper;
0041:        import org.apache.commons.betwixt.expression.CollectionUpdater;
0042:        import org.apache.commons.betwixt.expression.EmptyExpression;
0043:        import org.apache.commons.betwixt.expression.IteratorExpression;
0044:        import org.apache.commons.betwixt.expression.MapEntryAdder;
0045:        import org.apache.commons.betwixt.expression.MethodUpdater;
0046:        import org.apache.commons.betwixt.expression.StringExpression;
0047:        import org.apache.commons.betwixt.registry.DefaultXMLBeanInfoRegistry;
0048:        import org.apache.commons.betwixt.registry.PolymorphicReferenceResolver;
0049:        import org.apache.commons.betwixt.registry.XMLBeanInfoRegistry;
0050:        import org.apache.commons.betwixt.strategy.ClassNormalizer;
0051:        import org.apache.commons.betwixt.strategy.DefaultNameMapper;
0052:        import org.apache.commons.betwixt.strategy.DefaultPluralStemmer;
0053:        import org.apache.commons.betwixt.strategy.NameMapper;
0054:        import org.apache.commons.betwixt.strategy.PluralStemmer;
0055:        import org.apache.commons.betwixt.strategy.TypeBindingStrategy;
0056:        import org.apache.commons.logging.Log;
0057:        import org.apache.commons.logging.LogFactory;
0058:        import org.xml.sax.InputSource;
0059:        import org.xml.sax.SAXException;
0060:
0061:        /** 
0062:         * <p><code>XMLIntrospector</code> an introspector of beans to create a 
0063:         * XMLBeanInfo instance.</p>
0064:         *
0065:         * <p>By default, <code>XMLBeanInfo</code> caching is switched on.
0066:         * This means that the first time that a request is made for a <code>XMLBeanInfo</code>
0067:         * for a particular class, the <code>XMLBeanInfo</code> is cached.
0068:         * Later requests for the same class will return the cached value.</p>
0069:         * 
0070:         * <p>Note :</p>
0071:         * <p>This class makes use of the <code>java.bean.Introspector</code>
0072:         * class, which contains a BeanInfoSearchPath. To make sure betwixt can
0073:         * do his work correctly, this searchpath is completely ignored during 
0074:         * processing. The original values will be restored after processing finished
0075:         * </p>
0076:         * 
0077:         * @author <a href="mailto:jstrachan@apache.org">James Strachan</a>
0078:         * @author <a href="mailto:martin@mvdb.net">Martin van den Bemt</a>
0079:         */
0080:        public class XMLIntrospector {
0081:            /** 
0082:             * Log used for logging (Doh!) 
0083:             * @deprecated 0.6 use the {@link #getLog()} property instead
0084:             */
0085:            protected Log log = LogFactory.getLog(XMLIntrospector.class);
0086:
0087:            /** Maps classes to <code>XMLBeanInfo</code>'s */
0088:            private XMLBeanInfoRegistry registry;
0089:
0090:            /** Digester used to parse the XML descriptor files */
0091:            private XMLBeanInfoDigester digester;
0092:
0093:            /** Digester used to parse the multi-mapping XML descriptor files */
0094:            private MultiMappingBeanInfoDigester multiMappingdigester;
0095:
0096:            /** Configuration to be used for introspection*/
0097:            private IntrospectionConfiguration configuration;
0098:
0099:            /**
0100:             * Resolves polymorphic references.
0101:             * Though this is used only at bind time,
0102:             * it is typically tightly couple to the xml registry. 
0103:             * It is therefore convenient to keep both references together.
0104:             */
0105:            private PolymorphicReferenceResolver polymorphicReferenceResolver;
0106:
0107:            /** Base constructor */
0108:            public XMLIntrospector() {
0109:                this (new IntrospectionConfiguration());
0110:            }
0111:
0112:            /**
0113:             * Construct allows a custom configuration to be set on construction.
0114:             * This allows <code>IntrospectionConfiguration</code> subclasses
0115:             * to be easily used.
0116:             * @param configuration IntrospectionConfiguration, not null
0117:             */
0118:            public XMLIntrospector(IntrospectionConfiguration configuration) {
0119:                setConfiguration(configuration);
0120:                DefaultXMLBeanInfoRegistry defaultRegistry = new DefaultXMLBeanInfoRegistry();
0121:                setRegistry(defaultRegistry);
0122:                setPolymorphicReferenceResolver(defaultRegistry);
0123:            }
0124:
0125:            // Properties
0126:            //-------------------------------------------------------------------------   
0127:
0128:            /**
0129:             * <p>Gets the current logging implementation. </p>
0130:             * @return the Log implementation which this class logs to
0131:             */
0132:            public Log getLog() {
0133:                return getConfiguration().getIntrospectionLog();
0134:            }
0135:
0136:            /**
0137:             * <p>Sets the current logging implementation.</p>
0138:             * @param log the Log implementation to use for logging
0139:             */
0140:            public void setLog(Log log) {
0141:                getConfiguration().setIntrospectionLog(log);
0142:            }
0143:
0144:            /** 
0145:             * <p>Gets the current registry implementation.
0146:             * The registry is checked to see if it has an <code>XMLBeanInfo</code> for a class
0147:             * before introspecting. 
0148:             * After standard introspection is complete, the instance will be passed to the registry.</p>
0149:             *
0150:             * <p>This allows finely grained control over the caching strategy.
0151:             * It also allows the standard introspection mechanism 
0152:             * to be overridden on a per class basis.</p>
0153:             *
0154:             * @return the XMLBeanInfoRegistry currently used 
0155:             */
0156:            public XMLBeanInfoRegistry getRegistry() {
0157:                return registry;
0158:            }
0159:
0160:            /** 
0161:             * <p>Sets the <code>XMLBeanInfoRegistry</code> implementation.
0162:             * The registry is checked to see if it has an <code>XMLBeanInfo</code> for a class
0163:             * before introspecting. 
0164:             * After standard introspection is complete, the instance will be passed to the registry.</p>
0165:             *
0166:             * <p>This allows finely grained control over the caching strategy.
0167:             * It also allows the standard introspection mechanism 
0168:             * to be overridden on a per class basis.</p>
0169:             *
0170:             * <p><strong>Note</strong> when using polymophic mapping with a custom
0171:             * registry, a call to 
0172:             * {@link #setPolymorphicReferenceResolver(PolymorphicReferenceResolver)}
0173:             * may be necessary.
0174:             * </p>
0175:             * @param registry the XMLBeanInfoRegistry to use
0176:             */
0177:            public void setRegistry(XMLBeanInfoRegistry registry) {
0178:                this .registry = registry;
0179:            }
0180:
0181:            /**
0182:             * Gets the configuration to be used for introspection.
0183:             * The various introspection-time strategies 
0184:             * and configuration variables have been consolidated as properties
0185:             * of this bean.
0186:             * This allows the configuration to be more easily shared.
0187:             * @return IntrospectionConfiguration, not null
0188:             */
0189:            public IntrospectionConfiguration getConfiguration() {
0190:                return configuration;
0191:            }
0192:
0193:            /**
0194:             * Sets the configuration to be used for introspection.
0195:             * The various introspection-time strategies 
0196:             * and configuration variables have been consolidated as properties
0197:             * of this bean.
0198:             * This allows the configuration to be more easily shared.
0199:             * @param configuration IntrospectionConfiguration, not null
0200:             */
0201:            public void setConfiguration(
0202:                    IntrospectionConfiguration configuration) {
0203:                this .configuration = configuration;
0204:            }
0205:
0206:            /**
0207:             * Gets the <code>ClassNormalizer</code> strategy.
0208:             * This is used to determine the Class to be introspected
0209:             * (the normalized Class). 
0210:             *
0211:             * @return the <code>ClassNormalizer</code> used to determine the Class to be introspected
0212:             * for a given Object.
0213:             * @deprecated 0.6 use getConfiguration().getClassNormalizer
0214:             * @since 0.5
0215:             */
0216:            public ClassNormalizer getClassNormalizer() {
0217:                return getConfiguration().getClassNormalizer();
0218:            }
0219:
0220:            /**
0221:             * Sets the <code>ClassNormalizer</code> strategy.
0222:             * This is used to determine the Class to be introspected
0223:             * (the normalized Class). 
0224:             *
0225:             * @param classNormalizer the <code>ClassNormalizer</code> to be used to determine 
0226:             * the Class to be introspected for a given Object.
0227:             * @deprecated 0.6 use getConfiguration().setClassNormalizer
0228:             * @since 0.5
0229:             *
0230:             */
0231:            public void setClassNormalizer(ClassNormalizer classNormalizer) {
0232:                getConfiguration().setClassNormalizer(classNormalizer);
0233:            }
0234:
0235:            /**
0236:             * <p>Gets the resolver for polymorphic references.</p>
0237:             * <p>
0238:             * Though this is used only at bind time,
0239:             * it is typically tightly couple to the xml registry. 
0240:             * It is therefore convenient to keep both references together.
0241:             * </p>
0242:             * <p><strong>Note:</strong> though the implementation is
0243:             * set initially to the default registry,
0244:             * this reference is not updated when {@link #setRegistry(XMLBeanInfoRegistry)}
0245:             * is called. Therefore, a call to {@link #setPolymorphicReferenceResolver(PolymorphicReferenceResolver)}
0246:             * with the instance may be necessary. 
0247:             * </p>
0248:             * @since 0.7
0249:             * @return <code>PolymorphicReferenceResolver</code>, not null
0250:             */
0251:            public PolymorphicReferenceResolver getPolymorphicReferenceResolver() {
0252:                return polymorphicReferenceResolver;
0253:            }
0254:
0255:            /**
0256:             * <p>Sets the resolver for polymorphic references.</p>
0257:             * <p>
0258:             * Though this is used only at bind time,
0259:             * it is typically tightly couple to the xml registry. 
0260:             * It is therefore convenient to keep both references together.
0261:             * </p>
0262:             * <p><strong>Note:</strong> though the implementation is
0263:             * set initially to the default registry,
0264:             * this reference is not updated when {@link #setRegistry(XMLBeanInfoRegistry)}
0265:             * is called. Therefore, a call to {@link #setPolymorphicReferenceResolver(PolymorphicReferenceResolver)}
0266:             * with the instance may be necessary. 
0267:             * </p>
0268:             * @since 0.7
0269:             * @param polymorphicReferenceResolver The polymorphicReferenceResolver to set.
0270:             */
0271:            public void setPolymorphicReferenceResolver(
0272:                    PolymorphicReferenceResolver polymorphicReferenceResolver) {
0273:                this .polymorphicReferenceResolver = polymorphicReferenceResolver;
0274:            }
0275:
0276:            /** 
0277:             * Is <code>XMLBeanInfo</code> caching enabled? 
0278:             *
0279:             * @deprecated 0.5 replaced by XMlBeanInfoRegistry
0280:             * @return true if caching is enabled
0281:             */
0282:            public boolean isCachingEnabled() {
0283:                return true;
0284:            }
0285:
0286:            /**
0287:             * Set whether <code>XMLBeanInfo</code> caching should be enabled.
0288:             *
0289:             * @deprecated 0.5 replaced by XMlBeanInfoRegistry
0290:             * @param cachingEnabled ignored
0291:             */
0292:            public void setCachingEnabled(boolean cachingEnabled) {
0293:                //
0294:            }
0295:
0296:            /** 
0297:             * Should attributes (or elements) be used for primitive types.
0298:             * @return true if primitive types will be mapped to attributes in the introspection
0299:             * @deprecated 0.6 use getConfiguration().isAttributesForPrimitives
0300:             */
0301:            public boolean isAttributesForPrimitives() {
0302:                return getConfiguration().isAttributesForPrimitives();
0303:            }
0304:
0305:            /** 
0306:             * Set whether attributes (or elements) should be used for primitive types. 
0307:             * @param attributesForPrimitives pass trus to map primitives to attributes,
0308:             *        pass false to map primitives to elements
0309:             * @deprecated 0.6 use getConfiguration().setAttributesForPrimitives
0310:             */
0311:            public void setAttributesForPrimitives(
0312:                    boolean attributesForPrimitives) {
0313:                getConfiguration().setAttributesForPrimitives(
0314:                        attributesForPrimitives);
0315:            }
0316:
0317:            /**
0318:             * Should collections be wrapped in an extra element?
0319:             * 
0320:             * @return whether we should we wrap collections in an extra element? 
0321:             * @deprecated 0.6 use getConfiguration().isWrapCollectionsInElement
0322:             */
0323:            public boolean isWrapCollectionsInElement() {
0324:                return getConfiguration().isWrapCollectionsInElement();
0325:            }
0326:
0327:            /** 
0328:             * Sets whether we should we wrap collections in an extra element.
0329:             *
0330:             * @param wrapCollectionsInElement pass true if collections should be wrapped in a
0331:             *        parent element
0332:             * @deprecated 0.6 use getConfiguration().setWrapCollectionsInElement
0333:             */
0334:            public void setWrapCollectionsInElement(
0335:                    boolean wrapCollectionsInElement) {
0336:                getConfiguration().setWrapCollectionsInElement(
0337:                        wrapCollectionsInElement);
0338:            }
0339:
0340:            /** 
0341:             * Get singular and plural matching strategy.
0342:             *
0343:             * @return the strategy used to detect matching singular and plural properties 
0344:             * @deprecated 0.6 use getConfiguration().getPluralStemmer
0345:             */
0346:            public PluralStemmer getPluralStemmer() {
0347:                return getConfiguration().getPluralStemmer();
0348:            }
0349:
0350:            /** 
0351:             * Sets the strategy used to detect matching singular and plural properties 
0352:             *
0353:             * @param pluralStemmer the PluralStemmer used to match singular and plural
0354:             * @deprecated 0.6 use getConfiguration().setPluralStemmer 
0355:             */
0356:            public void setPluralStemmer(PluralStemmer pluralStemmer) {
0357:                getConfiguration().setPluralStemmer(pluralStemmer);
0358:            }
0359:
0360:            /** 
0361:             * Gets the name mapper strategy.
0362:             * 
0363:             * @return the strategy used to convert bean type names into element names
0364:             * @deprecated 0.5 getNameMapper is split up in 
0365:             * {@link #getElementNameMapper()} and {@link #getAttributeNameMapper()}
0366:             */
0367:            public NameMapper getNameMapper() {
0368:                return getElementNameMapper();
0369:            }
0370:
0371:            /** 
0372:             * Sets the strategy used to convert bean type names into element names
0373:             * @param nameMapper the NameMapper strategy to be used
0374:             * @deprecated 0.5 setNameMapper is split up in 
0375:             * {@link #setElementNameMapper(NameMapper)} and {@link #setAttributeNameMapper(NameMapper)}
0376:             */
0377:            public void setNameMapper(NameMapper nameMapper) {
0378:                setElementNameMapper(nameMapper);
0379:            }
0380:
0381:            /**
0382:             * Gets the name mapping strategy used to convert bean names into elements.
0383:             *
0384:             * @return the strategy used to convert bean type names into element 
0385:             * names. If no element mapper is currently defined then a default one is created.
0386:             * @deprecated 0.6 use getConfiguration().getElementNameMapper
0387:             */
0388:            public NameMapper getElementNameMapper() {
0389:                return getConfiguration().getElementNameMapper();
0390:            }
0391:
0392:            /**
0393:             * Sets the strategy used to convert bean type names into element names
0394:             * @param nameMapper the NameMapper to use for the conversion
0395:             * @deprecated 0.6 use getConfiguration().setElementNameMapper
0396:             */
0397:            public void setElementNameMapper(NameMapper nameMapper) {
0398:                getConfiguration().setElementNameMapper(nameMapper);
0399:            }
0400:
0401:            /**
0402:             * Gets the name mapping strategy used to convert bean names into attributes.
0403:             *
0404:             * @return the strategy used to convert bean type names into attribute
0405:             * names. If no attributeNamemapper is known, it will default to the ElementNameMapper
0406:             * @deprecated 0.6 getConfiguration().getAttributeNameMapper
0407:             */
0408:            public NameMapper getAttributeNameMapper() {
0409:                return getConfiguration().getAttributeNameMapper();
0410:            }
0411:
0412:            /**
0413:             * Sets the strategy used to convert bean type names into attribute names
0414:             * @param nameMapper the NameMapper to use for the convertion
0415:             * @deprecated 0.6 use getConfiguration().setAttributeNameMapper
0416:             */
0417:            public void setAttributeNameMapper(NameMapper nameMapper) {
0418:                getConfiguration().setAttributeNameMapper(nameMapper);
0419:            }
0420:
0421:            /**
0422:             * Should the original <code>java.reflect.Introspector</code> bean info search path be used?
0423:             * By default it will be false.
0424:             * 
0425:             * @return boolean if the beanInfoSearchPath should be used.
0426:             * @deprecated 0.6 use getConfiguration().useBeanInfoSearchPath
0427:             */
0428:            public boolean useBeanInfoSearchPath() {
0429:                return getConfiguration().useBeanInfoSearchPath();
0430:            }
0431:
0432:            /**
0433:             * Specifies if you want to use the beanInfoSearchPath 
0434:             * @see java.beans.Introspector for more details
0435:             * @param useBeanInfoSearchPath 
0436:             * @deprecated 0.6 use getConfiguration().setUseBeanInfoSearchPath
0437:             */
0438:            public void setUseBeanInfoSearchPath(boolean useBeanInfoSearchPath) {
0439:                getConfiguration().setUseBeanInfoSearchPath(
0440:                        useBeanInfoSearchPath);
0441:            }
0442:
0443:            // Methods
0444:            //------------------------------------------------------------------------- 
0445:
0446:            /**
0447:             * Flush existing cached <code>XMLBeanInfo</code>'s.
0448:             *
0449:             * @deprecated 0.5 use flushable registry instead
0450:             */
0451:            public void flushCache() {
0452:            }
0453:
0454:            /** Create a standard <code>XMLBeanInfo</code> by introspection
0455:             * The actual introspection depends only on the <code>BeanInfo</code>
0456:             * associated with the bean.
0457:             * 
0458:             * @param bean introspect this bean
0459:             * @return XMLBeanInfo describing bean-xml mapping
0460:             * @throws IntrospectionException when the bean introspection fails
0461:             */
0462:            public XMLBeanInfo introspect(Object bean)
0463:                    throws IntrospectionException {
0464:                if (getLog().isDebugEnabled()) {
0465:                    getLog().debug("Introspecting...");
0466:                    getLog().debug(bean);
0467:                }
0468:
0469:                if (bean instanceof  DynaBean) {
0470:                    // allow DynaBean implementations to be overridden by .betwixt files
0471:                    XMLBeanInfo xmlBeanInfo = findByXMLDescriptor(bean
0472:                            .getClass());
0473:                    if (xmlBeanInfo != null) {
0474:                        return xmlBeanInfo;
0475:                    }
0476:                    // this is DynaBean use the DynaClass for introspection
0477:                    return introspect(((DynaBean) bean).getDynaClass());
0478:
0479:                } else {
0480:                    // normal bean so normal introspection
0481:                    Class normalClass = getClassNormalizer()
0482:                            .getNormalizedClass(bean);
0483:                    return introspect(normalClass);
0484:                }
0485:            }
0486:
0487:            /**
0488:             * Creates XMLBeanInfo by reading the DynaProperties of a DynaBean.
0489:             * Customizing DynaBeans using betwixt is not supported.
0490:             * 
0491:             * @param dynaClass the DynaBean to introspect
0492:             * 
0493:             * @return XMLBeanInfo for the DynaClass
0494:             */
0495:            public XMLBeanInfo introspect(DynaClass dynaClass) {
0496:
0497:                // for now this method does not do much, since XMLBeanInfoRegistry cannot
0498:                // use a DynaClass as a key
0499:                // TODO: add caching for DynaClass XMLBeanInfo
0500:                // need to work out if this is possible
0501:
0502:                // this line allows subclasses to change creation strategy
0503:                XMLBeanInfo xmlInfo = createXMLBeanInfo(dynaClass);
0504:
0505:                // populate the created info with 
0506:                DynaClassBeanType beanClass = new DynaClassBeanType(dynaClass);
0507:                populate(xmlInfo, beanClass);
0508:
0509:                return xmlInfo;
0510:            }
0511:
0512:            /**
0513:             * <p>Introspects the given <code>Class</code> using the dot betwixt 
0514:             * document in the given <code>InputSource</code>.
0515:             * </p>
0516:             * <p>
0517:             * <strong>Note:</strong> that the given mapping will <em>not</em>
0518:             * be registered by this method. Use {@link #register(Class, InputSource)}
0519:             * instead.
0520:             * </p>
0521:             * @since 0.7
0522:             * @param aClass <code>Class</code>, not null
0523:             * @param source <code>InputSource</code>, not null
0524:             * @return <code>XMLBeanInfo</code> describing the mapping.
0525:             * @throws SAXException when the input source cannot be parsed
0526:             * @throws IOException 	
0527:             */
0528:            public synchronized XMLBeanInfo introspect(Class aClass,
0529:                    InputSource source) throws IOException, SAXException {
0530:                // need to synchronize since we only use one instance and SAX is essentially one thread only
0531:                configureDigester(aClass);
0532:                XMLBeanInfo result = (XMLBeanInfo) digester.parse(source);
0533:                return result;
0534:            }
0535:
0536:            /** Create a standard <code>XMLBeanInfo</code> by introspection.
0537:             * The actual introspection depends only on the <code>BeanInfo</code>
0538:             * associated with the bean.    
0539:             *    
0540:             * @param aClass introspect this class
0541:             * @return XMLBeanInfo describing bean-xml mapping
0542:             * @throws IntrospectionException when the bean introspection fails
0543:             */
0544:            public XMLBeanInfo introspect(Class aClass)
0545:                    throws IntrospectionException {
0546:                // we first reset the beaninfo searchpath.
0547:                String[] searchPath = null;
0548:                if (!getConfiguration().useBeanInfoSearchPath()) {
0549:                    try {
0550:                        searchPath = Introspector.getBeanInfoSearchPath();
0551:                        Introspector.setBeanInfoSearchPath(new String[] {});
0552:                    } catch (SecurityException e) {
0553:                        // this call may fail in some environments
0554:                        getLog()
0555:                                .warn(
0556:                                        "Security manager does not allow bean info search path to be set");
0557:                        getLog()
0558:                                .debug(
0559:                                        "Security exception whilst setting bean info search page",
0560:                                        e);
0561:                    }
0562:                }
0563:
0564:                XMLBeanInfo xmlInfo = registry.get(aClass);
0565:
0566:                if (xmlInfo == null) {
0567:                    // lets see if we can find an XML descriptor first
0568:                    if (getLog().isDebugEnabled()) {
0569:                        getLog().debug(
0570:                                "Attempting to lookup an XML descriptor for class: "
0571:                                        + aClass);
0572:                    }
0573:
0574:                    xmlInfo = findByXMLDescriptor(aClass);
0575:                    if (xmlInfo == null) {
0576:                        BeanInfo info;
0577:                        if (getConfiguration().ignoreAllBeanInfo()) {
0578:                            info = Introspector.getBeanInfo(aClass,
0579:                                    Introspector.IGNORE_ALL_BEANINFO);
0580:                        } else {
0581:                            info = Introspector.getBeanInfo(aClass);
0582:                        }
0583:                        xmlInfo = introspect(info);
0584:                    }
0585:
0586:                    if (xmlInfo != null) {
0587:                        registry.put(aClass, xmlInfo);
0588:                    }
0589:                } else {
0590:                    getLog().trace("Used cached XMLBeanInfo.");
0591:                }
0592:
0593:                if (getLog().isTraceEnabled()) {
0594:                    getLog().trace(xmlInfo);
0595:                }
0596:                if (!getConfiguration().useBeanInfoSearchPath()
0597:                        && searchPath != null) {
0598:                    try {
0599:                        // we restore the beaninfo searchpath.
0600:                        Introspector.setBeanInfoSearchPath(searchPath);
0601:                    } catch (SecurityException e) {
0602:                        // this call may fail in some environments
0603:                        getLog()
0604:                                .warn(
0605:                                        "Security manager does not allow bean info search path to be set");
0606:                        getLog()
0607:                                .debug(
0608:                                        "Security exception whilst setting bean info search page",
0609:                                        e);
0610:                    }
0611:                }
0612:
0613:                return xmlInfo;
0614:            }
0615:
0616:            /** Create a standard <code>XMLBeanInfo</code> by introspection. 
0617:             * The actual introspection depends only on the <code>BeanInfo</code>
0618:             * associated with the bean.
0619:             *
0620:             * @param beanInfo the BeanInfo the xml-bean mapping is based on
0621:             * @return XMLBeanInfo describing bean-xml mapping
0622:             * @throws IntrospectionException when the bean introspection fails
0623:             */
0624:            public XMLBeanInfo introspect(BeanInfo beanInfo)
0625:                    throws IntrospectionException {
0626:                XMLBeanInfo xmlBeanInfo = createXMLBeanInfo(beanInfo);
0627:                populate(xmlBeanInfo, new JavaBeanType(beanInfo));
0628:                return xmlBeanInfo;
0629:            }
0630:
0631:            /**
0632:             * <p>Registers the class mappings specified in the multi-class document
0633:             * given by the <code>InputSource</code>.
0634:             * </p>
0635:             * <p>
0636:             * <strong>Note:</strong> that this method will override any existing mapping
0637:             * for the speficied classes.
0638:             * </p>
0639:             * @since 0.7
0640:             * @param source <code>InputSource</code>, not null
0641:             * @return <code>Class</code> array containing all mapped classes
0642:             * @throws IntrospectionException
0643:             * @throws SAXException
0644:             * @throws IOException
0645:             */
0646:            public synchronized Class[] register(InputSource source)
0647:                    throws IntrospectionException, IOException, SAXException {
0648:                Map xmlBeanInfoByClass = loadMultiMapping(source);
0649:                Set keySet = xmlBeanInfoByClass.keySet();
0650:                Class mappedClasses[] = new Class[keySet.size()];
0651:                int i = 0;
0652:                for (Iterator it = keySet.iterator(); it.hasNext();) {
0653:                    Class clazz = (Class) it.next();
0654:                    mappedClasses[i++] = clazz;
0655:                    XMLBeanInfo xmlBeanInfo = (XMLBeanInfo) xmlBeanInfoByClass
0656:                            .get(clazz);
0657:                    if (xmlBeanInfo != null) {
0658:                        getRegistry().put(clazz, xmlBeanInfo);
0659:                    }
0660:                }
0661:                return mappedClasses;
0662:            }
0663:
0664:            /**
0665:             * Loads the multi-mapping from the given <code>InputSource</code>.
0666:             * @param mapping <code>InputSource</code>, not null
0667:             * @return <code>Map</code> containing <code>XMLBeanInfo</code>'s
0668:             * indexes by the <code>Class</code> they describe
0669:             * @throws IOException
0670:             * @throws SAXException
0671:             */
0672:            private synchronized Map loadMultiMapping(InputSource mapping)
0673:                    throws IOException, SAXException {
0674:                // synchronized method so this digester is only used by
0675:                // one thread at once
0676:                if (multiMappingdigester == null) {
0677:                    multiMappingdigester = new MultiMappingBeanInfoDigester();
0678:                    multiMappingdigester.setXMLIntrospector(this );
0679:                }
0680:                Map multiBeanInfoMap = (Map) multiMappingdigester
0681:                        .parse(mapping);
0682:                return multiBeanInfoMap;
0683:            }
0684:
0685:            /**
0686:             * <p>Registers the class mapping specified in the standard dot-betwixt file.
0687:             * Subsequent introspections will use this registered mapping for the class.
0688:             * </p>
0689:             * <p>
0690:             * <strong>Note:</strong> that this method will override any existing mapping
0691:             * for this class.
0692:             * </p>
0693:             * @since 0.7
0694:             * @param aClass <code>Class</code>, not null
0695:             * @param source <code>InputSource</code>, not null
0696:             * @throws SAXException when the source cannot be parsed
0697:             * @throws IOException 
0698:             */
0699:            public void register(Class aClass, InputSource source)
0700:                    throws IOException, SAXException {
0701:                XMLBeanInfo xmlBeanInfo = introspect(aClass, source);
0702:                getRegistry().put(aClass, xmlBeanInfo);
0703:            }
0704:
0705:            /**
0706:             * Populates the given <code>XMLBeanInfo</code> based on the given type of bean.
0707:             *
0708:             * @param xmlBeanInfo populate this, not null
0709:             * @param bean the type definition for the bean, not null
0710:             */
0711:            private void populate(XMLBeanInfo xmlBeanInfo, BeanType bean) {
0712:                String name = bean.getBeanName();
0713:
0714:                ElementDescriptor elementDescriptor = new ElementDescriptor();
0715:                elementDescriptor.setLocalName(getElementNameMapper()
0716:                        .mapTypeToElementName(name));
0717:                elementDescriptor.setPropertyType(bean.getElementType());
0718:
0719:                if (getLog().isTraceEnabled()) {
0720:                    getLog().trace("Populating:" + bean);
0721:                }
0722:
0723:                // add default string value for primitive types
0724:                if (bean.isPrimitiveType()) {
0725:                    getLog().trace("Bean is primitive");
0726:                    elementDescriptor.setTextExpression(StringExpression
0727:                            .getInstance());
0728:
0729:                } else {
0730:
0731:                    getLog().trace("Bean is standard type");
0732:
0733:                    boolean isLoopType = bean.isLoopType();
0734:
0735:                    List elements = new ArrayList();
0736:                    List attributes = new ArrayList();
0737:                    List contents = new ArrayList();
0738:
0739:                    // add bean properties for all collection which are not basic
0740:                    if (!(isLoopType && isBasicCollection(bean.getClass()))) {
0741:                        addProperties(bean.getProperties(), elements,
0742:                                attributes, contents);
0743:                    }
0744:
0745:                    // add iterator for collections
0746:                    if (isLoopType) {
0747:                        getLog().trace("Bean is loop");
0748:                        ElementDescriptor loopDescriptor = new ElementDescriptor();
0749:                        loopDescriptor.setCollective(true);
0750:                        loopDescriptor.setHollow(true);
0751:                        loopDescriptor.setSingularPropertyType(Object.class);
0752:                        loopDescriptor
0753:                                .setContextExpression(new IteratorExpression(
0754:                                        EmptyExpression.getInstance()));
0755:                        loopDescriptor.setUpdater(CollectionUpdater
0756:                                .getInstance());
0757:                        if (bean.isMapType()) {
0758:                            loopDescriptor.setQualifiedName("entry");
0759:                        }
0760:                        elements.add(loopDescriptor);
0761:                    }
0762:
0763:                    int size = elements.size();
0764:                    if (size > 0) {
0765:                        ElementDescriptor[] descriptors = new ElementDescriptor[size];
0766:                        elements.toArray(descriptors);
0767:                        elementDescriptor.setElementDescriptors(descriptors);
0768:                    }
0769:                    size = attributes.size();
0770:                    if (size > 0) {
0771:                        AttributeDescriptor[] descriptors = new AttributeDescriptor[size];
0772:                        attributes.toArray(descriptors);
0773:                        elementDescriptor.setAttributeDescriptors(descriptors);
0774:                    }
0775:                    size = contents.size();
0776:                    if (size > 0) {
0777:                        if (size > 0) {
0778:                            Descriptor[] descriptors = new Descriptor[size];
0779:                            contents.toArray(descriptors);
0780:                            elementDescriptor
0781:                                    .setContentDescriptors(descriptors);
0782:                        }
0783:                    }
0784:                }
0785:
0786:                xmlBeanInfo.setElementDescriptor(elementDescriptor);
0787:
0788:                // default any addProperty() methods
0789:                defaultAddMethods(elementDescriptor, bean.getElementType());
0790:
0791:                if (getLog().isTraceEnabled()) {
0792:                    getLog().trace("Populated descriptor:");
0793:                    getLog().trace(elementDescriptor);
0794:                }
0795:            }
0796:
0797:            /**
0798:             * <p>Is the given type a basic collection?
0799:             * </p><p>
0800:             * This is used to determine whether a collective type
0801:             * should be introspected as a bean (in addition to a collection).
0802:             * </p>
0803:             * @param type <code>Class</code>, not null
0804:             * @return
0805:             */
0806:            private boolean isBasicCollection(Class type) {
0807:                return type.getName().startsWith("java.util");
0808:            }
0809:
0810:            /**
0811:             * Creates XMLBeanInfo for the given DynaClass.
0812:             * 
0813:             * @param dynaClass the class describing a DynaBean
0814:             * 
0815:             * @return XMLBeanInfo that describes the properties of the given 
0816:             * DynaClass
0817:             */
0818:            protected XMLBeanInfo createXMLBeanInfo(DynaClass dynaClass) {
0819:                // XXX is the chosen class right?
0820:                XMLBeanInfo beanInfo = new XMLBeanInfo(dynaClass.getClass());
0821:                return beanInfo;
0822:            }
0823:
0824:            /** 
0825:             * Create a XML descriptor from a bean one. 
0826:             * Go through and work out whether it's a loop property, a primitive or a standard.
0827:             * The class property is ignored.
0828:             *
0829:             * @param propertyDescriptor create a <code>NodeDescriptor</code> for this property
0830:             * @param useAttributesForPrimitives write primitives as attributes (rather than elements)
0831:             * @return a correctly configured <code>NodeDescriptor</code> for the property
0832:             * @throws IntrospectionException when bean introspection fails
0833:             * @deprecated 0.5 use {@link #createXMLDescriptor}.
0834:             */
0835:            public Descriptor createDescriptor(
0836:                    PropertyDescriptor propertyDescriptor,
0837:                    boolean useAttributesForPrimitives)
0838:                    throws IntrospectionException {
0839:                return createXMLDescriptor(new BeanProperty(propertyDescriptor));
0840:            }
0841:
0842:            /** 
0843:             * Create a XML descriptor from a bean one. 
0844:             * Go through and work out whether it's a loop property, a primitive or a standard.
0845:             * The class property is ignored.
0846:             *
0847:             * @param beanProperty the BeanProperty specifying the property
0848:             * @return a correctly configured <code>NodeDescriptor</code> for the property
0849:             * @since 0.5
0850:             */
0851:            public Descriptor createXMLDescriptor(BeanProperty beanProperty) {
0852:                return beanProperty.createXMLDescriptor(configuration);
0853:            }
0854:
0855:            /** 
0856:             * Add any addPropety(PropertyType) methods as Updaters 
0857:             * which are often used for 1-N relationships in beans.
0858:             * This method does not preserve null property names.
0859:             * <br>
0860:             * The tricky part here is finding which ElementDescriptor corresponds
0861:             * to the method. e.g. a property 'items' might have an Element descriptor
0862:             * which the method addItem() should match to. 
0863:             * <br>
0864:             * So the algorithm we'll use 
0865:             * by default is to take the decapitalized name of the property being added
0866:             * and find the first ElementDescriptor that matches the property starting with
0867:             * the string. This should work for most use cases. 
0868:             * e.g. addChild() would match the children property.
0869:             * <br>
0870:             * TODO this probably needs refactoring. It probably belongs in the bean wrapper
0871:             * (so that it'll work properly with dyna-beans) and so that the operations can 
0872:             * be optimized by caching. Multiple hash maps are created and getMethods is
0873:             * called multiple times. This is relatively expensive and so it'd be better
0874:             * to push into a proper class and cache.
0875:             * <br>
0876:             * 
0877:             * @param rootDescriptor add defaults to this descriptor
0878:             * @param beanClass the <code>Class</code> to which descriptor corresponds
0879:             */
0880:            public void defaultAddMethods(ElementDescriptor rootDescriptor,
0881:                    Class beanClass) {
0882:                defaultAddMethods(rootDescriptor, beanClass, false);
0883:            }
0884:
0885:            /** 
0886:             * Add any addPropety(PropertyType) methods as Updaters 
0887:             * which are often used for 1-N relationships in beans.
0888:             * <br>
0889:             * The tricky part here is finding which ElementDescriptor corresponds
0890:             * to the method. e.g. a property 'items' might have an Element descriptor
0891:             * which the method addItem() should match to. 
0892:             * <br>
0893:             * So the algorithm we'll use 
0894:             * by default is to take the decapitalized name of the property being added
0895:             * and find the first ElementDescriptor that matches the property starting with
0896:             * the string. This should work for most use cases. 
0897:             * e.g. addChild() would match the children property.
0898:             * <br>
0899:             * TODO this probably needs refactoring. It probably belongs in the bean wrapper
0900:             * (so that it'll work properly with dyna-beans) and so that the operations can 
0901:             * be optimized by caching. Multiple hash maps are created and getMethods is
0902:             * called multiple times. This is relatively expensive and so it'd be better
0903:             * to push into a proper class and cache.
0904:             * <br>
0905:             * 
0906:             * @param rootDescriptor add defaults to this descriptor
0907:             * @param beanClass the <code>Class</code> to which descriptor corresponds
0908:             * @since 0.8
0909:             */
0910:            public void defaultAddMethods(ElementDescriptor rootDescriptor,
0911:                    Class beanClass, boolean preservePropertyName) {
0912:                // TODO: this probably does work properly with DynaBeans: need to push
0913:                // implementation into an class and expose it on BeanType.  
0914:
0915:                // lets iterate over all methods looking for one of the form
0916:                // add*(PropertyType)
0917:                if (beanClass != null) {
0918:                    ArrayList singleParameterAdders = new ArrayList();
0919:                    ArrayList twinParameterAdders = new ArrayList();
0920:
0921:                    Method[] methods = beanClass.getMethods();
0922:                    for (int i = 0, size = methods.length; i < size; i++) {
0923:                        Method method = methods[i];
0924:                        String name = method.getName();
0925:                        if (name.startsWith("add")) {
0926:                            // TODO: should we filter out non-void returning methods?
0927:                            // some beans will return something as a helper
0928:                            Class[] types = method.getParameterTypes();
0929:                            if (types != null) {
0930:                                if (getLog().isTraceEnabled()) {
0931:                                    getLog()
0932:                                            .trace(
0933:                                                    "Searching for match for "
0934:                                                            + method);
0935:                                }
0936:
0937:                                switch (types.length) {
0938:                                case 1:
0939:                                    singleParameterAdders.add(method);
0940:                                    break;
0941:                                case 2:
0942:                                    twinParameterAdders.add(method);
0943:                                    break;
0944:                                default:
0945:                                    // ignore
0946:                                    break;
0947:                                }
0948:                            }
0949:                        }
0950:                    }
0951:
0952:                    Map elementsByPropertyName = makeElementDescriptorMap(rootDescriptor);
0953:
0954:                    for (Iterator it = singleParameterAdders.iterator(); it
0955:                            .hasNext();) {
0956:                        Method singleParameterAdder = (Method) it.next();
0957:                        setIteratorAdder(elementsByPropertyName,
0958:                                singleParameterAdder, preservePropertyName);
0959:                    }
0960:
0961:                    for (Iterator it = twinParameterAdders.iterator(); it
0962:                            .hasNext();) {
0963:                        Method twinParameterAdder = (Method) it.next();
0964:                        setMapAdder(elementsByPropertyName, twinParameterAdder);
0965:                    }
0966:
0967:                    // need to call this once all the defaults have been added
0968:                    // so that all the singular types have been set correctly
0969:                    configureMappingDerivation(rootDescriptor);
0970:                }
0971:            }
0972:
0973:            /**
0974:             * Configures the mapping derivation according to the current
0975:             * <code>MappingDerivationStrategy</code> implementation.
0976:             * This method acts recursively.
0977:             * @param rootDescriptor <code>ElementDescriptor</code>, not null
0978:             */
0979:            private void configureMappingDerivation(ElementDescriptor descriptor) {
0980:                boolean useBindTime = getConfiguration()
0981:                        .getMappingDerivationStrategy()
0982:                        .useBindTimeTypeForMapping(
0983:                                descriptor.getPropertyType(),
0984:                                descriptor.getSingularPropertyType());
0985:                descriptor.setUseBindTimeTypeForMapping(useBindTime);
0986:                ElementDescriptor[] childDescriptors = descriptor
0987:                        .getElementDescriptors();
0988:                for (int i = 0, size = childDescriptors.length; i < size; i++) {
0989:                    configureMappingDerivation(childDescriptors[i]);
0990:                }
0991:            }
0992:
0993:            /**
0994:             * Sets the adder method where the corresponding property is an iterator
0995:             * @param rootDescriptor
0996:             * @param singleParameterAdder
0997:             */
0998:            private void setIteratorAdder(Map elementsByPropertyName,
0999:                    Method singleParameterAdderMethod,
1000:                    boolean preserveNullPropertyName) {
1001:
1002:                String adderName = singleParameterAdderMethod.getName();
1003:                String propertyName = Introspector.decapitalize(adderName
1004:                        .substring(3));
1005:                ElementDescriptor matchingDescriptor = getMatchForAdder(
1006:                        propertyName, elementsByPropertyName);
1007:                if (matchingDescriptor != null) {
1008:                    //TODO defensive code: probably should check descriptor type
1009:
1010:                    Class singularType = singleParameterAdderMethod
1011:                            .getParameterTypes()[0];
1012:                    if (getLog().isTraceEnabled()) {
1013:                        getLog().trace(adderName + "->" + propertyName);
1014:                    }
1015:                    // this may match a standard collection or iteration
1016:                    getLog().trace("Matching collection or iteration");
1017:
1018:                    matchingDescriptor.setUpdater(new MethodUpdater(
1019:                            singleParameterAdderMethod));
1020:                    matchingDescriptor.setSingularPropertyType(singularType);
1021:                    matchingDescriptor
1022:                            .setHollow(!isPrimitiveType(singularType));
1023:                    String localName = matchingDescriptor.getLocalName();
1024:                    if (!preserveNullPropertyName
1025:                            && (localName == null || localName.length() == 0)) {
1026:                        matchingDescriptor.setLocalName(getConfiguration()
1027:                                .getElementNameMapper().mapTypeToElementName(
1028:                                        propertyName));
1029:                    }
1030:
1031:                    if (getLog().isDebugEnabled()) {
1032:                        getLog().debug("!! " + singleParameterAdderMethod);
1033:                        getLog().debug("!! " + singularType);
1034:                    }
1035:                }
1036:            }
1037:
1038:            /**
1039:             * Sets the adder where the corresponding property type is an map
1040:             * @param rootDescriptor
1041:             * @param singleParameterAdder
1042:             */
1043:            private void setMapAdder(Map elementsByPropertyName,
1044:                    Method twinParameterAdderMethod) {
1045:                String adderName = twinParameterAdderMethod.getName();
1046:                String propertyName = Introspector.decapitalize(adderName
1047:                        .substring(3));
1048:                ElementDescriptor matchingDescriptor = getMatchForAdder(
1049:                        propertyName, elementsByPropertyName);
1050:                assignAdder(twinParameterAdderMethod, matchingDescriptor);
1051:            }
1052:
1053:            /**
1054:             * Assigns the given method as an adder method to the given descriptor.
1055:             * @param twinParameterAdderMethod adder <code>Method</code>, not null
1056:             * @param matchingDescriptor <code>ElementDescriptor</code> describing the element
1057:             * @since 0.8
1058:             */
1059:            public void assignAdder(Method twinParameterAdderMethod,
1060:                    ElementDescriptor matchingDescriptor) {
1061:                if (matchingDescriptor != null
1062:                        && Map.class.isAssignableFrom(matchingDescriptor
1063:                                .getPropertyType())) {
1064:                    // this may match a map
1065:                    getLog().trace("Matching map");
1066:                    ElementDescriptor[] children = matchingDescriptor
1067:                            .getElementDescriptors();
1068:                    // see if the descriptor's been set up properly
1069:                    if (children.length == 0) {
1070:                        getLog().info(
1071:                                "'entry' descriptor is missing for map. "
1072:                                        + "Updaters cannot be set");
1073:
1074:                    } else {
1075:                        assignAdder(twinParameterAdderMethod, children);
1076:                    }
1077:                }
1078:            }
1079:
1080:            /**
1081:             * Assigns the given method as an adder.
1082:             * @param twinParameterAdderMethod adder <code>Method</code>, not null 
1083:             * @param children <code>ElementDescriptor</code> children, not null
1084:             */
1085:            private void assignAdder(Method twinParameterAdderMethod,
1086:                    ElementDescriptor[] children) {
1087:                Class[] types = twinParameterAdderMethod.getParameterTypes();
1088:                Class keyType = types[0];
1089:                Class valueType = types[1];
1090:
1091:                // loop through children 
1092:                // adding updaters for key and value
1093:                MapEntryAdder adder = new MapEntryAdder(
1094:                        twinParameterAdderMethod);
1095:                for (int n = 0, noOfGrandChildren = children.length; n < noOfGrandChildren; n++) {
1096:                    if ("key".equals(children[n].getLocalName())) {
1097:
1098:                        children[n].setUpdater(adder.getKeyUpdater());
1099:                        children[n].setSingularPropertyType(keyType);
1100:                        if (children[n].getPropertyType() == null) {
1101:                            children[n].setPropertyType(valueType);
1102:                        }
1103:                        if (isPrimitiveType(keyType)) {
1104:                            children[n].setHollow(false);
1105:                        }
1106:                        if (getLog().isTraceEnabled()) {
1107:                            getLog().trace("Key descriptor: " + children[n]);
1108:                        }
1109:
1110:                    } else if ("value".equals(children[n].getLocalName())) {
1111:
1112:                        children[n].setUpdater(adder.getValueUpdater());
1113:                        children[n].setSingularPropertyType(valueType);
1114:                        if (children[n].getPropertyType() == null) {
1115:                            children[n].setPropertyType(valueType);
1116:                        }
1117:                        if (isPrimitiveType(valueType)) {
1118:                            children[n].setHollow(false);
1119:                        }
1120:                        if (isLoopType(valueType)) {
1121:                            // need to attach a hollow descriptor
1122:                            // don't know the element name
1123:                            // so use null name (to match anything)
1124:                            ElementDescriptor loopDescriptor = new ElementDescriptor();
1125:                            loopDescriptor.setHollow(true);
1126:                            loopDescriptor.setSingularPropertyType(valueType);
1127:                            loopDescriptor.setPropertyType(valueType);
1128:                            children[n].addElementDescriptor(loopDescriptor);
1129:                            loopDescriptor.setCollective(true);
1130:                        }
1131:                        if (getLog().isTraceEnabled()) {
1132:                            getLog().trace("Value descriptor: " + children[n]);
1133:                        }
1134:                    }
1135:                }
1136:            }
1137:
1138:            /**
1139:             * Gets an ElementDescriptor for the property matching the adder
1140:             * @param adderName
1141:             * @param rootDescriptor
1142:             * @return
1143:             */
1144:            private ElementDescriptor getMatchForAdder(String propertyName,
1145:                    Map elementsByPropertyName) {
1146:                ElementDescriptor matchingDescriptor = null;
1147:                if (propertyName.length() > 0) {
1148:                    if (getLog().isTraceEnabled()) {
1149:                        getLog().trace(
1150:                                "findPluralDescriptor( " + propertyName
1151:                                        + " ):root property name="
1152:                                        + propertyName);
1153:                    }
1154:
1155:                    PluralStemmer stemmer = getPluralStemmer();
1156:                    matchingDescriptor = stemmer.findPluralDescriptor(
1157:                            propertyName, elementsByPropertyName);
1158:
1159:                    if (getLog().isTraceEnabled()) {
1160:                        getLog().trace(
1161:                                "findPluralDescriptor( " + propertyName
1162:                                        + " ):ElementDescriptor="
1163:                                        + matchingDescriptor);
1164:                    }
1165:                }
1166:                return matchingDescriptor;
1167:            }
1168:
1169:            // Implementation methods
1170:            //------------------------------------------------------------------------- 
1171:
1172:            /**
1173:             * Creates a map where the keys are the property names and the values are the ElementDescriptors
1174:             */
1175:            private Map makeElementDescriptorMap(
1176:                    ElementDescriptor rootDescriptor) {
1177:                Map result = new HashMap();
1178:                String rootPropertyName = rootDescriptor.getPropertyName();
1179:                if (rootPropertyName != null) {
1180:                    result.put(rootPropertyName, rootDescriptor);
1181:                }
1182:                makeElementDescriptorMap(rootDescriptor, result);
1183:                return result;
1184:            }
1185:
1186:            /**
1187:             * Creates a map where the keys are the property names and the values are the ElementDescriptors
1188:             * 
1189:             * @param rootDescriptor the values of the maps are the children of this 
1190:             * <code>ElementDescriptor</code> index by their property names
1191:             * @param map the map to which the elements will be added
1192:             */
1193:            private void makeElementDescriptorMap(
1194:                    ElementDescriptor rootDescriptor, Map map) {
1195:                ElementDescriptor[] children = rootDescriptor
1196:                        .getElementDescriptors();
1197:                if (children != null) {
1198:                    for (int i = 0, size = children.length; i < size; i++) {
1199:                        ElementDescriptor child = children[i];
1200:                        String propertyName = child.getPropertyName();
1201:                        if (propertyName != null) {
1202:                            map.put(propertyName, child);
1203:                        }
1204:                        makeElementDescriptorMap(child, map);
1205:                    }
1206:                }
1207:            }
1208:
1209:            /** 
1210:             * A Factory method to lazily create a new strategy 
1211:             * to detect matching singular and plural properties.
1212:             *
1213:             * @return new defualt PluralStemmer implementation
1214:             * @deprecated 0.6 this method has been moved into IntrospectionConfiguration.
1215:             * Those who need to vary this should subclass that class instead
1216:             */
1217:            protected PluralStemmer createPluralStemmer() {
1218:                return new DefaultPluralStemmer();
1219:            }
1220:
1221:            /** 
1222:             * A Factory method to lazily create a strategy 
1223:             * used to convert bean type names into element names.
1224:             *
1225:             * @return new default NameMapper implementation
1226:             * @deprecated 0.6 this method has been moved into IntrospectionConfiguration.
1227:             * Those who need to vary this should subclass that class instead
1228:             */
1229:            protected NameMapper createNameMapper() {
1230:                return new DefaultNameMapper();
1231:            }
1232:
1233:            /** 
1234:             * Attempt to lookup the XML descriptor for the given class using the
1235:             * classname + ".betwixt" using the same ClassLoader used to load the class
1236:             * or return null if it could not be loaded
1237:             * 
1238:             * @param aClass digester .betwixt file for this class
1239:             * @return XMLBeanInfo digested from the .betwixt file if one can be found.
1240:             *         Otherwise null.
1241:             */
1242:            protected synchronized XMLBeanInfo findByXMLDescriptor(Class aClass) {
1243:                // trim the package name
1244:                String name = aClass.getName();
1245:                int idx = name.lastIndexOf('.');
1246:                if (idx >= 0) {
1247:                    name = name.substring(idx + 1);
1248:                }
1249:                name += ".betwixt";
1250:
1251:                URL url = aClass.getResource(name);
1252:                if (url != null) {
1253:                    try {
1254:                        String urlText = url.toString();
1255:                        if (getLog().isDebugEnabled()) {
1256:                            getLog().debug(
1257:                                    "Parsing Betwixt XML descriptor: "
1258:                                            + urlText);
1259:                        }
1260:                        // synchronized method so this digester is only used by
1261:                        // one thread at once
1262:                        configureDigester(aClass);
1263:                        return (XMLBeanInfo) digester.parse(urlText);
1264:                    } catch (Exception e) {
1265:                        getLog().warn(
1266:                                "Caught exception trying to parse: " + name, e);
1267:                    }
1268:                }
1269:
1270:                if (getLog().isTraceEnabled()) {
1271:                    getLog().trace("Could not find betwixt file " + name);
1272:                }
1273:                return null;
1274:            }
1275:
1276:            /**
1277:             * Configures the single <code>Digester</code> instance used by this introspector.
1278:             * @param aClass <code>Class</code>, not null
1279:             */
1280:            private synchronized void configureDigester(Class aClass) {
1281:                if (digester == null) {
1282:                    digester = new XMLBeanInfoDigester();
1283:                    digester.setXMLIntrospector(this );
1284:                }
1285:                digester.setBeanClass(aClass);
1286:            }
1287:
1288:            /** 
1289:             * Loop through properties and process each one 
1290:             *
1291:             * @param beanInfo the BeanInfo whose properties will be processed
1292:             * @param elements ElementDescriptor list to which elements will be added
1293:             * @param attributes AttributeDescriptor list to which attributes will be added
1294:             * @param contents Descriptor list to which mixed content will be added
1295:             * @throws IntrospectionException if the bean introspection fails
1296:             * @deprecated 0.5 use {@link #addProperties(BeanProperty[], List, List,List)}
1297:             */
1298:            protected void addProperties(BeanInfo beanInfo, List elements,
1299:                    List attributes, List contents)
1300:                    throws IntrospectionException {
1301:                PropertyDescriptor[] descriptors = beanInfo
1302:                        .getPropertyDescriptors();
1303:                if (descriptors != null) {
1304:                    for (int i = 0, size = descriptors.length; i < size; i++) {
1305:                        addProperty(beanInfo, descriptors[i], elements,
1306:                                attributes, contents);
1307:                    }
1308:                }
1309:                if (getLog().isTraceEnabled()) {
1310:                    getLog().trace(elements);
1311:                    getLog().trace(attributes);
1312:                    getLog().trace(contents);
1313:                }
1314:            }
1315:
1316:            /** 
1317:             * Loop through properties and process each one 
1318:             *
1319:             * @param beanProperties the properties to be processed
1320:             * @param elements ElementDescriptor list to which elements will be added
1321:             * @param attributes AttributeDescriptor list to which attributes will be added
1322:             * @param contents Descriptor list to which mixed content will be added
1323:             * @since 0.5
1324:             */
1325:            protected void addProperties(BeanProperty[] beanProperties,
1326:                    List elements, List attributes, List contents) {
1327:                if (beanProperties != null) {
1328:                    if (getLog().isTraceEnabled()) {
1329:                        getLog().trace(
1330:                                beanProperties.length
1331:                                        + " properties to be added");
1332:                    }
1333:                    for (int i = 0, size = beanProperties.length; i < size; i++) {
1334:                        addProperty(beanProperties[i], elements, attributes,
1335:                                contents);
1336:                    }
1337:                }
1338:                if (getLog().isTraceEnabled()) {
1339:                    getLog()
1340:                            .trace(
1341:                                    "After properties have been added (elements, attributes, contents):");
1342:                    getLog().trace(elements);
1343:                    getLog().trace(attributes);
1344:                    getLog().trace(contents);
1345:                }
1346:            }
1347:
1348:            /** 
1349:             * Process a property. 
1350:             * Go through and work out whether it's a loop property, a primitive or a standard.
1351:             * The class property is ignored.
1352:             *
1353:             * @param beanInfo the BeanInfo whose property is being processed
1354:             * @param propertyDescriptor the PropertyDescriptor to process
1355:             * @param elements ElementDescriptor list to which elements will be added
1356:             * @param attributes AttributeDescriptor list to which attributes will be added
1357:             * @param contents Descriptor list to which mixed content will be added
1358:             * @throws IntrospectionException if the bean introspection fails
1359:             * @deprecated 0.5 BeanInfo is no longer required. 
1360:             * Use {@link #addProperty(PropertyDescriptor, List, List, List)} instead.
1361:             */
1362:            protected void addProperty(BeanInfo beanInfo,
1363:                    PropertyDescriptor propertyDescriptor, List elements,
1364:                    List attributes, List contents)
1365:                    throws IntrospectionException {
1366:                addProperty(propertyDescriptor, elements, attributes, contents);
1367:            }
1368:
1369:            /** 
1370:             * Process a property. 
1371:             * Go through and work out whether it's a loop property, a primitive or a standard.
1372:             * The class property is ignored.
1373:             *
1374:             * @param propertyDescriptor the PropertyDescriptor to process
1375:             * @param elements ElementDescriptor list to which elements will be added
1376:             * @param attributes AttributeDescriptor list to which attributes will be added
1377:             * @param contents Descriptor list to which mixed content will be added
1378:             * @throws IntrospectionException if the bean introspection fails
1379:             * @deprecated 0.5 use {@link #addProperty(BeanProperty, List, List, List)} instead
1380:             */
1381:            protected void addProperty(PropertyDescriptor propertyDescriptor,
1382:                    List elements, List attributes, List contents)
1383:                    throws IntrospectionException {
1384:                addProperty(new BeanProperty(propertyDescriptor), elements,
1385:                        attributes, contents);
1386:            }
1387:
1388:            /** 
1389:             * Process a property. 
1390:             * Go through and work out whether it's a loop property, a primitive or a standard.
1391:             * The class property is ignored.
1392:             *
1393:             * @param beanProperty the bean property to process
1394:             * @param elements ElementDescriptor list to which elements will be added
1395:             * @param attributes AttributeDescriptor list to which attributes will be added
1396:             * @param contents Descriptor list to which mixed content will be added
1397:             * @since 0.5
1398:             */
1399:            protected void addProperty(BeanProperty beanProperty,
1400:                    List elements, List attributes, List contents) {
1401:                Descriptor nodeDescriptor = createXMLDescriptor(beanProperty);
1402:                if (nodeDescriptor == null) {
1403:                    return;
1404:                }
1405:                if (nodeDescriptor instanceof  ElementDescriptor) {
1406:                    elements.add(nodeDescriptor);
1407:                } else if (nodeDescriptor instanceof  AttributeDescriptor) {
1408:                    attributes.add(nodeDescriptor);
1409:                } else {
1410:                    contents.add(nodeDescriptor);
1411:                }
1412:            }
1413:
1414:            /** 
1415:             * Loop through properties and process each one 
1416:             *
1417:             * @param beanInfo the BeanInfo whose properties will be processed
1418:             * @param elements ElementDescriptor list to which elements will be added
1419:             * @param attributes AttributeDescriptor list to which attributes will be added
1420:             * @throws IntrospectionException if the bean introspection fails
1421:             * @deprecated 0.5 this method does not support mixed content. 
1422:             * Use {@link #addProperties(BeanInfo, List, List, List)} instead.
1423:             */
1424:            protected void addProperties(BeanInfo beanInfo, List elements,
1425:                    List attributes) throws IntrospectionException {
1426:                PropertyDescriptor[] descriptors = beanInfo
1427:                        .getPropertyDescriptors();
1428:                if (descriptors != null) {
1429:                    for (int i = 0, size = descriptors.length; i < size; i++) {
1430:                        addProperty(beanInfo, descriptors[i], elements,
1431:                                attributes);
1432:                    }
1433:                }
1434:                if (getLog().isTraceEnabled()) {
1435:                    getLog().trace(elements);
1436:                    getLog().trace(attributes);
1437:                }
1438:            }
1439:
1440:            /** 
1441:             * Process a property. 
1442:             * Go through and work out whether it's a loop property, a primitive or a standard.
1443:             * The class property is ignored.
1444:             *
1445:             * @param beanInfo the BeanInfo whose property is being processed
1446:             * @param propertyDescriptor the PropertyDescriptor to process
1447:             * @param elements ElementDescriptor list to which elements will be added
1448:             * @param attributes AttributeDescriptor list to which attributes will be added
1449:             * @throws IntrospectionException if the bean introspection fails
1450:             * @deprecated 0.5 this method does not support mixed content. 
1451:             * Use {@link #addProperty(BeanInfo, PropertyDescriptor, List, List, List)} instead.
1452:             */
1453:            protected void addProperty(BeanInfo beanInfo,
1454:                    PropertyDescriptor propertyDescriptor, List elements,
1455:                    List attributes) throws IntrospectionException {
1456:                NodeDescriptor nodeDescriptor = XMLIntrospectorHelper
1457:                        .createDescriptor(propertyDescriptor,
1458:                                isAttributesForPrimitives(), this );
1459:                if (nodeDescriptor == null) {
1460:                    return;
1461:                }
1462:                if (nodeDescriptor instanceof  ElementDescriptor) {
1463:                    elements.add(nodeDescriptor);
1464:                } else {
1465:                    attributes.add(nodeDescriptor);
1466:                }
1467:            }
1468:
1469:            /** 
1470:             * Factory method to create XMLBeanInfo instances 
1471:             *
1472:             * @param beanInfo the BeanInfo from which the XMLBeanInfo will be created
1473:             * @return XMLBeanInfo describing the bean-xml mapping
1474:             */
1475:            protected XMLBeanInfo createXMLBeanInfo(BeanInfo beanInfo) {
1476:                XMLBeanInfo xmlBeanInfo = new XMLBeanInfo(beanInfo
1477:                        .getBeanDescriptor().getBeanClass());
1478:                return xmlBeanInfo;
1479:            }
1480:
1481:            /** 
1482:             * Is this class a loop?
1483:             *
1484:             * @param type the Class to test
1485:             * @return true if the type is a loop type 
1486:             */
1487:            public boolean isLoopType(Class type) {
1488:                return getConfiguration().isLoopType(type);
1489:            }
1490:
1491:            /** 
1492:             * Is this class a primitive?
1493:             * 
1494:             * @param type the Class to test
1495:             * @return true for primitive types 
1496:             */
1497:            public boolean isPrimitiveType(Class type) {
1498:                // TODO: this method will probably be deprecated when primitive types
1499:                // are subsumed into the simple type concept 
1500:                TypeBindingStrategy.BindingType bindingType = configuration
1501:                        .getTypeBindingStrategy().bindingType(type);
1502:                boolean result = (bindingType
1503:                        .equals(TypeBindingStrategy.BindingType.PRIMITIVE));
1504:                return result;
1505:            }
1506:
1507:            /** Some type of pseudo-bean */
1508:            private abstract class BeanType {
1509:                /** 
1510:                 * Gets the name for this bean type 
1511:                 * @return the bean type name, not null
1512:                 */
1513:                public abstract String getBeanName();
1514:
1515:                /** 
1516:                 * Gets the type to be used by the associated element
1517:                 * @return a Class that is the type not null
1518:                 */
1519:                public abstract Class getElementType();
1520:
1521:                /**
1522:                 * Is this type a primitive?
1523:                 * @return true if this type should be treated by betwixt as a primitive
1524:                 */
1525:                public abstract boolean isPrimitiveType();
1526:
1527:                /**
1528:                 * is this type a map?
1529:                 * @return true this should be treated as a map.
1530:                 */
1531:                public abstract boolean isMapType();
1532:
1533:                /** 
1534:                 * Is this type a loop?
1535:                 * @return true if this should be treated as a loop
1536:                 */
1537:                public abstract boolean isLoopType();
1538:
1539:                /**
1540:                 * Gets the properties associated with this bean.
1541:                 * @return the BeanProperty's, not null
1542:                 */
1543:                public abstract BeanProperty[] getProperties();
1544:
1545:                /**
1546:                 * Create string representation
1547:                 * @return something useful for logging
1548:                 */
1549:                public String toString() {
1550:                    return "Bean[name=" + getBeanName() + ", type="
1551:                            + getElementType();
1552:                }
1553:            }
1554:
1555:            /** Supports standard Java Beans */
1556:            private class JavaBeanType extends BeanType {
1557:                /** Introspected bean */
1558:                private BeanInfo beanInfo;
1559:                /** Bean class */
1560:                private Class beanClass;
1561:                /** Bean name */
1562:                private String name;
1563:                /** Bean properties */
1564:                private BeanProperty[] properties;
1565:
1566:                /**
1567:                 * Constructs a BeanType for a standard Java Bean
1568:                 * @param beanInfo the BeanInfo describing the standard Java Bean, not null
1569:                 */
1570:                public JavaBeanType(BeanInfo beanInfo) {
1571:                    this .beanInfo = beanInfo;
1572:                    BeanDescriptor beanDescriptor = beanInfo
1573:                            .getBeanDescriptor();
1574:                    beanClass = beanDescriptor.getBeanClass();
1575:                    name = beanDescriptor.getName();
1576:                    // Array's contain a bad character
1577:                    if (beanClass.isArray()) {
1578:                        // called all array's Array
1579:                        name = "Array";
1580:                    }
1581:
1582:                }
1583:
1584:                /** @see BeanType #getElementType */
1585:                public Class getElementType() {
1586:                    return beanClass;
1587:                }
1588:
1589:                /** @see BeanType#getBeanName */
1590:                public String getBeanName() {
1591:                    return name;
1592:                }
1593:
1594:                /** @see BeanType#isPrimitiveType */
1595:                public boolean isPrimitiveType() {
1596:                    return XMLIntrospector.this .isPrimitiveType(beanClass);
1597:                }
1598:
1599:                /** @see BeanType#isLoopType */
1600:                public boolean isLoopType() {
1601:                    return getConfiguration().isLoopType(beanClass);
1602:                }
1603:
1604:                /** @see BeanType#isMapType */
1605:                public boolean isMapType() {
1606:                    return Map.class.isAssignableFrom(beanClass);
1607:                }
1608:
1609:                /** @see BeanType#getProperties */
1610:                public BeanProperty[] getProperties() {
1611:                    // lazy creation
1612:                    if (properties == null) {
1613:                        ArrayList propertyDescriptors = new ArrayList();
1614:                        // add base bean info
1615:                        PropertyDescriptor[] descriptors = beanInfo
1616:                                .getPropertyDescriptors();
1617:                        if (descriptors != null) {
1618:                            for (int i = 0, size = descriptors.length; i < size; i++) {
1619:                                if (!getConfiguration()
1620:                                        .getPropertySuppressionStrategy()
1621:                                        .suppressProperty(
1622:                                                beanClass,
1623:                                                descriptors[i]
1624:                                                        .getPropertyType(),
1625:                                                descriptors[i].getName())) {
1626:                                    propertyDescriptors.add(descriptors[i]);
1627:                                }
1628:                            }
1629:                        }
1630:
1631:                        // add properties from additional bean infos
1632:                        BeanInfo[] additionals = beanInfo
1633:                                .getAdditionalBeanInfo();
1634:                        if (additionals != null) {
1635:                            for (int i = 0, outerSize = additionals.length; i < outerSize; i++) {
1636:                                BeanInfo additionalInfo = additionals[i];
1637:                                descriptors = additionalInfo
1638:                                        .getPropertyDescriptors();
1639:                                if (descriptors != null) {
1640:                                    for (int j = 0, innerSize = descriptors.length; j < innerSize; j++) {
1641:                                        if (!getConfiguration()
1642:                                                .getPropertySuppressionStrategy()
1643:                                                .suppressProperty(
1644:                                                        beanClass,
1645:                                                        descriptors[j]
1646:                                                                .getPropertyType(),
1647:                                                        descriptors[j]
1648:                                                                .getName())) {
1649:                                            propertyDescriptors
1650:                                                    .add(descriptors[j]);
1651:                                        }
1652:                                    }
1653:                                }
1654:                            }
1655:                        }
1656:
1657:                        addAllSuperinterfaces(beanClass, propertyDescriptors);
1658:
1659:                        // what happens when size is zero?
1660:                        properties = new BeanProperty[propertyDescriptors
1661:                                .size()];
1662:                        int count = 0;
1663:                        for (Iterator it = propertyDescriptors.iterator(); it
1664:                                .hasNext(); count++) {
1665:                            PropertyDescriptor propertyDescriptor = (PropertyDescriptor) it
1666:                                    .next();
1667:                            properties[count] = new BeanProperty(
1668:                                    propertyDescriptor);
1669:                        }
1670:                    }
1671:                    return properties;
1672:                }
1673:
1674:                /**
1675:                 * Adds all super interfaces.
1676:                 * Super interface methods are not returned within the usual 
1677:                 * bean info for an interface.
1678:                 * @param clazz <code>Class</code>, not null
1679:                 * @param propertyDescriptors <code>ArrayList</code> of <code>PropertyDescriptor</code>s', not null
1680:                 */
1681:                private void addAllSuperinterfaces(Class clazz,
1682:                        ArrayList propertyDescriptors) {
1683:                    if (clazz.isInterface()) {
1684:                        Class[] super interfaces = clazz.getInterfaces();
1685:                        for (int i = 0, size = super interfaces.length; i < size; i++) {
1686:                            try {
1687:
1688:                                BeanInfo beanInfo;
1689:                                if (getConfiguration().ignoreAllBeanInfo()) {
1690:                                    beanInfo = Introspector.getBeanInfo(
1691:                                            super interfaces[i],
1692:                                            Introspector.IGNORE_ALL_BEANINFO);
1693:                                } else {
1694:                                    beanInfo = Introspector
1695:                                            .getBeanInfo(super interfaces[i]);
1696:                                }
1697:                                PropertyDescriptor[] descriptors = beanInfo
1698:                                        .getPropertyDescriptors();
1699:                                for (int j = 0, descriptorLength = descriptors.length; j < descriptorLength; j++) {
1700:                                    if (!getConfiguration()
1701:                                            .getPropertySuppressionStrategy()
1702:                                            .suppressProperty(
1703:                                                    beanClass,
1704:                                                    descriptors[j]
1705:                                                            .getPropertyType(),
1706:                                                    descriptors[j].getName())) {
1707:                                        propertyDescriptors.add(descriptors[j]);
1708:                                    }
1709:                                }
1710:                                addAllSuperinterfaces(super interfaces[i],
1711:                                        propertyDescriptors);
1712:
1713:                            } catch (IntrospectionException ex) {
1714:                                log
1715:                                        .info(
1716:                                                "Introspection on superinterface failed.",
1717:                                                ex);
1718:                            }
1719:                        }
1720:                    }
1721:                }
1722:
1723:            }
1724:
1725:            /** Implementation for DynaClasses */
1726:            private class DynaClassBeanType extends BeanType {
1727:                /** BeanType for this DynaClass */
1728:                private DynaClass dynaClass;
1729:                /** Properties extracted in constuctor */
1730:                private BeanProperty[] properties;
1731:
1732:                /** 
1733:                 * Constructs a BeanType for a DynaClass
1734:                 * @param dynaClass not null
1735:                 */
1736:                public DynaClassBeanType(DynaClass dynaClass) {
1737:                    this .dynaClass = dynaClass;
1738:                    DynaProperty[] dynaProperties = dynaClass
1739:                            .getDynaProperties();
1740:                    properties = new BeanProperty[dynaProperties.length];
1741:                    for (int i = 0, size = dynaProperties.length; i < size; i++) {
1742:                        properties[i] = new BeanProperty(dynaProperties[i]);
1743:                    }
1744:                }
1745:
1746:                /** @see BeanType#getBeanName */
1747:                public String getBeanName() {
1748:                    return dynaClass.getName();
1749:                }
1750:
1751:                /** @see BeanType#getElementType */
1752:                public Class getElementType() {
1753:                    return DynaClass.class;
1754:                }
1755:
1756:                /** @see BeanType#isPrimitiveType */
1757:                public boolean isPrimitiveType() {
1758:                    return false;
1759:                }
1760:
1761:                /** @see BeanType#isMapType */
1762:                public boolean isMapType() {
1763:                    return false;
1764:                }
1765:
1766:                /** @see BeanType#isLoopType */
1767:                public boolean isLoopType() {
1768:                    return false;
1769:                }
1770:
1771:                /** @see BeanType#getProperties */
1772:                public BeanProperty[] getProperties() {
1773:                    return properties;
1774:                }
1775:            }
1776:        }
www.java2java.com | Contact Us
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.