001 /* 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 package org.apache.commons.betwixt.digester; 018 019 import java.beans.BeanInfo; 020 import java.beans.Introspector; 021 import java.beans.PropertyDescriptor; 022 023 import org.apache.commons.logging.Log; 024 import org.apache.commons.logging.LogFactory; 025 026 /** <p>Factors out common code used by Betwixt rules that access bean properties. 027 * Maybe a lot of this should be moved into <code>BeanUtils</code>.</p> 028 * 029 * @author Robert Burrell Donkin 030 * @since 0.5 031 */ 032 public abstract class MappedPropertyRule extends RuleSupport { 033 034 /** Logger */ 035 private static final Log log = LogFactory.getLog( MappedPropertyRule.class ); 036 /** Base constructor */ 037 public MappedPropertyRule() { 038 } 039 040 041 042 // Implementation methods 043 //------------------------------------------------------------------------- 044 045 /** 046 * Returns the property descriptor for the class and property name. 047 * Note that some caching could be used to improve performance of 048 * this method. Or this method could be added to PropertyUtils. 049 * 050 * @param beanClass descriptor for property in this class 051 * @param propertyName descriptor for property with this name 052 * @return property descriptor for the named property in the given class 053 */ 054 protected PropertyDescriptor getPropertyDescriptor( Class beanClass, 055 String propertyName ) { 056 if ( beanClass != null && propertyName != null ) { 057 if (log.isTraceEnabled()) { 058 log.trace("Searching for property " + propertyName + " on " + beanClass); 059 } 060 try { 061 // TODO: replace this call to introspector to an object call 062 // which finds all property descriptors for a class 063 // this allows extra property descriptors to be added 064 BeanInfo beanInfo; 065 if( getXMLIntrospector().getConfiguration().ignoreAllBeanInfo() ) { 066 beanInfo = Introspector.getBeanInfo( beanClass, Introspector.IGNORE_ALL_BEANINFO ); 067 } 068 else { 069 beanInfo = Introspector.getBeanInfo( beanClass ); 070 } 071 PropertyDescriptor[] descriptors = 072 beanInfo.getPropertyDescriptors(); 073 if ( descriptors != null ) { 074 for ( int i = 0, size = descriptors.length; i < size; i++ ) { 075 PropertyDescriptor descriptor = descriptors[i]; 076 if ( propertyName.equals( descriptor.getName() ) ) { 077 log.trace("Found matching method."); 078 return descriptor; 079 } 080 } 081 } 082 // for interfaces, check all super interfaces 083 if (beanClass.isInterface()) { 084 Class[] superinterfaces = beanClass.getInterfaces(); 085 for (int i=0, size=superinterfaces.length; i<size; i++) { 086 PropertyDescriptor descriptor = getPropertyDescriptor(superinterfaces[i], propertyName); 087 if (descriptor != null) 088 { 089 return descriptor; 090 } 091 } 092 } 093 094 log.trace("No match found."); 095 return null; 096 } catch (Exception e) { 097 log.warn( "Caught introspection exception", e ); 098 } 099 } 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 }