View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    * 
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   * 
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */ 
17  package org.apache.commons.betwixt.digester;
18  
19  import java.beans.BeanInfo;
20  import java.beans.Introspector;
21  import java.beans.PropertyDescriptor;
22  
23  import org.apache.commons.logging.Log;
24  import org.apache.commons.logging.LogFactory;
25  
26  /** <p>Factors out common code used by Betwixt rules that access bean properties.
27    * Maybe a lot of this should be moved into <code>BeanUtils</code>.</p>
28    *
29    * @author Robert Burrell Donkin
30    * @since 0.5
31    */
32  public abstract class MappedPropertyRule extends RuleSupport {
33  
34      /** Logger */
35      private static final Log log = LogFactory.getLog( MappedPropertyRule.class );   
36      /** Base constructor */
37      public MappedPropertyRule() {
38      }
39      
40      
41  
42      // Implementation methods
43      //-------------------------------------------------------------------------    
44  
45      /** 
46       * Returns the property descriptor for the class and property name.
47       * Note that some caching could be used to improve performance of 
48       * this method. Or this method could be added to PropertyUtils.
49       *
50       * @param beanClass descriptor for property in this class
51       * @param propertyName descriptor for property with this name
52       * @return property descriptor for the named property in the given class 
53       */
54      protected PropertyDescriptor getPropertyDescriptor( Class beanClass, 
55                                                          String propertyName ) {
56          if ( beanClass != null && propertyName != null ) {
57              if (log.isTraceEnabled()) {
58                  log.trace("Searching for property " + propertyName + " on " + beanClass);
59              }
60              try {
61                  // TODO: replace this call to introspector to an object call
62                  // which finds all property descriptors for a class
63                  // this allows extra property descriptors to be added 
64                  BeanInfo beanInfo;
65                  if( getXMLIntrospector().getConfiguration().ignoreAllBeanInfo() ) {
66                      beanInfo = Introspector.getBeanInfo( beanClass, Introspector.IGNORE_ALL_BEANINFO );
67                  }
68                  else {
69                      beanInfo = Introspector.getBeanInfo( beanClass );
70                  }
71                  PropertyDescriptor[] descriptors = 
72                      beanInfo.getPropertyDescriptors();
73                  if ( descriptors != null ) {
74                      for ( int i = 0, size = descriptors.length; i < size; i++ ) {
75                          PropertyDescriptor descriptor = descriptors[i];
76                          if ( propertyName.equals( descriptor.getName() ) ) {
77                              log.trace("Found matching method.");
78                              return descriptor;
79                          }
80                      }
81                  }
82                  // for interfaces, check all super interfaces
83                  if (beanClass.isInterface()) {
84                      Class[] superinterfaces = beanClass.getInterfaces();
85                      for (int i=0, size=superinterfaces.length; i<size; i++) {
86                          PropertyDescriptor descriptor = getPropertyDescriptor(superinterfaces[i], propertyName);
87                          if (descriptor != null)
88                          {
89                              return descriptor;
90                          }
91                      }
92                  }
93                  
94                  log.trace("No match found.");
95                  return null;
96              } catch (Exception e) {
97                  log.warn( "Caught introspection exception", e );
98              }
99          }
100         return null;
101     }
102     
103     
104     /**
105      * Gets the type of a property
106      *
107      * @param propertyClassName class name for property type (may be null)
108      * @param beanClass class that has property 
109      * @param propertyName the name of the property whose type is to be determined
110      * @return property type 
111      */
112     protected Class getPropertyType( String propertyClassName, 
113                                      Class beanClass, String propertyName ) {
114         // XXX: should use a ClassLoader to handle 
115         //      complex class loading situations
116         if ( propertyClassName != null ) {
117             try {
118                 Class answer = loadClass(propertyClassName);
119                 if (answer != null) {
120                     if (log.isTraceEnabled()) {
121                         log.trace("Used specified type " + answer);
122                     }
123                     return answer;
124                 }
125             } catch (Exception e) {
126                 log.warn("Cannot load specified type", e);
127             }
128         }
129         
130         PropertyDescriptor descriptor = 
131             getPropertyDescriptor( beanClass, propertyName );        
132         if ( descriptor != null ) { 
133             return descriptor.getPropertyType();
134         }
135         
136         if (log.isTraceEnabled()) {
137             log.trace("Cannot find property type.");
138             log.trace("  className=" + propertyClassName 
139                         + " base=" + beanClass + " name=" + propertyName);
140         }
141         return null;            
142     }
143 }