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       /*** Classloader used to load classes by name */
37      private ClassLoader classLoader;
38      /*** Base constructor */
39      public MappedPropertyRule() {
40          this.classLoader = getClass().getClassLoader();
41      }
42      
43      
44  
45      // Implementation methods
46      //-------------------------------------------------------------------------    
47  
48      /*** 
49       * Returns the property descriptor for the class and property name.
50       * Note that some caching could be used to improve performance of 
51       * this method. Or this method could be added to PropertyUtils.
52       *
53       * @param beanClass descriptor for property in this class
54       * @param propertyName descriptor for property with this name
55       * @return property descriptor for the named property in the given class 
56       */
57      protected PropertyDescriptor getPropertyDescriptor( Class beanClass, 
58                                                          String propertyName ) {
59          if ( beanClass != null && propertyName != null ) {
60              if (log.isTraceEnabled()) {
61                  log.trace("Searching for property " + propertyName + " on " + beanClass);
62              }
63              try {
64                  // TODO: replace this call to introspector to an object call
65                  // which finds all property descriptors for a class
66                  // this allows extra property descriptors to be added 
67                  BeanInfo beanInfo;
68                  if( getXMLIntrospector().getConfiguration().ignoreAllBeanInfo() ) {
69                      beanInfo = Introspector.getBeanInfo( beanClass, Introspector.IGNORE_ALL_BEANINFO );
70                  }
71                  else {
72                      beanInfo = Introspector.getBeanInfo( beanClass );
73                  }
74                  PropertyDescriptor[] descriptors = 
75                      beanInfo.getPropertyDescriptors();
76                  if ( descriptors != null ) {
77                      for ( int i = 0, size = descriptors.length; i < size; i++ ) {
78                          PropertyDescriptor descriptor = descriptors[i];
79                          if ( propertyName.equals( descriptor.getName() ) ) {
80                              log.trace("Found matching method.");
81                              return descriptor;
82                          }
83                      }
84                  }
85                  // for interfaces, check all super interfaces
86                  if (beanClass.isInterface()) {
87                      Class[] superinterfaces = beanClass.getInterfaces();
88                      for (int i=0, size=superinterfaces.length; i<size; i++) {
89                          PropertyDescriptor descriptor = getPropertyDescriptor(superinterfaces[i], propertyName);
90                          if (descriptor != null)
91                          {
92                              return descriptor;
93                          }
94                      }
95                  }
96                  
97                  log.trace("No match found.");
98                  return null;
99              } catch (Exception e) {
100                 log.warn( "Caught introspection exception", e );
101             }
102         }
103         return null;
104     }
105     
106     
107     /***
108      * Gets the type of a property
109      *
110      * @param propertyClassName class name for property type (may be null)
111      * @param beanClass class that has property 
112      * @param propertyName the name of the property whose type is to be determined
113      * @return property type 
114      */
115     protected Class getPropertyType( String propertyClassName, 
116                                      Class beanClass, String propertyName ) {
117         // XXX: should use a ClassLoader to handle 
118         //      complex class loading situations
119         if ( propertyClassName != null ) {
120             try {
121                 Class answer = classLoader.loadClass(propertyClassName);
122                 if (answer != null) {
123                     if (log.isTraceEnabled()) {
124                         log.trace("Used specified type " + answer);
125                     }
126                     return answer;
127                 }
128             } catch (Exception e) {
129                 log.warn("Cannot load specified type", e);
130             }
131         }
132         
133         PropertyDescriptor descriptor = 
134             getPropertyDescriptor( beanClass, propertyName );        
135         if ( descriptor != null ) { 
136             return descriptor.getPropertyType();
137         }
138         
139         if (log.isTraceEnabled()) {
140             log.trace("Cannot find property type.");
141             log.trace("  className=" + propertyClassName 
142                         + " base=" + beanClass + " name=" + propertyName);
143         }
144         return null;            
145     }
146 }