Coverage Report - org.apache.commons.ognl.internal.entry.PropertyDescriptorCacheEntryFactory
 
Classes in this File Line Coverage Branch Coverage Complexity
PropertyDescriptorCacheEntryFactory
88%
72/81
87%
65/74
11.75
 
 1  
 package org.apache.commons.ognl.internal.entry;
 2  
 
 3  
 /*
 4  
  * Licensed to the Apache Software Foundation (ASF) under one
 5  
  * or more contributor license agreements.  See the NOTICE file
 6  
  * distributed with this work for additional information
 7  
  * regarding copyright ownership.  The ASF licenses this file
 8  
  * to you under the Apache License, Version 2.0 (the
 9  
  * "License"); you may not use this file except in compliance
 10  
  * with the License.  You may obtain a copy of the License at
 11  
  *
 12  
  *   http://www.apache.org/licenses/LICENSE-2.0
 13  
  *
 14  
  * Unless required by applicable law or agreed to in writing,
 15  
  * software distributed under the License is distributed on an
 16  
  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 17  
  * KIND, either express or implied.  See the License for the
 18  
  * specific language governing permissions and limitations
 19  
  * under the License.
 20  
  */
 21  
 
 22  
 /*
 23  
  * $Id: PropertyDescriptorCacheEntryFactory.java 1430159 2013-01-08 07:40:04Z lukaszlenart $
 24  
  */
 25  
 
 26  
 import org.apache.commons.ognl.ObjectIndexedPropertyDescriptor;
 27  
 import org.apache.commons.ognl.OgnlException;
 28  
 import org.apache.commons.ognl.OgnlRuntime;
 29  
 import org.apache.commons.ognl.internal.CacheException;
 30  
 
 31  
 import java.beans.IntrospectionException;
 32  
 import java.beans.Introspector;
 33  
 import java.beans.PropertyDescriptor;
 34  
 import java.lang.reflect.Method;
 35  
 import java.util.ArrayList;
 36  
 import java.util.HashMap;
 37  
 import java.util.List;
 38  
 import java.util.Map;
 39  
 
 40  85
 public class PropertyDescriptorCacheEntryFactory
 41  
     implements ClassCacheEntryFactory<Map<String, PropertyDescriptor>>
 42  
 {
 43  
     public Map<String, PropertyDescriptor> create( Class<?> targetClass )
 44  
         throws CacheException
 45  
     {
 46  83
         Map<String, PropertyDescriptor> result = new HashMap<String, PropertyDescriptor>( 101 );
 47  
         PropertyDescriptor[] pda;
 48  
         try
 49  
         {
 50  83
             pda = Introspector.getBeanInfo( targetClass ).getPropertyDescriptors();
 51  
 
 52  866
             for (PropertyDescriptor aPda : pda) {
 53  
                 // workaround for Introspector bug 6528714 (bugs.sun.com)
 54  783
                 if (aPda.getReadMethod() != null && !OgnlRuntime.isMethodCallable(aPda.getReadMethod())) {
 55  2
                     aPda.setReadMethod(
 56  
                             findClosestMatchingMethod(targetClass, aPda.getReadMethod(), aPda.getName(),
 57  
                                     aPda.getPropertyType(), true));
 58  
                 }
 59  783
                 if (aPda.getWriteMethod() != null && !OgnlRuntime.isMethodCallable(aPda.getWriteMethod())) {
 60  1
                     aPda.setWriteMethod(
 61  
                             findClosestMatchingMethod(targetClass, aPda.getWriteMethod(), aPda.getName(),
 62  
                                     aPda.getPropertyType(), false));
 63  
                 }
 64  
 
 65  783
                 result.put(aPda.getName(), aPda);
 66  
             }
 67  
 
 68  83
             findObjectIndexedPropertyDescriptors( targetClass, result );
 69  
         }
 70  0
         catch ( IntrospectionException e )
 71  
         {
 72  0
             throw new CacheException( e );
 73  
         }
 74  0
         catch ( OgnlException e )
 75  
         {
 76  0
             throw new CacheException( e );
 77  83
         }
 78  83
         return result;
 79  
     }
 80  
 
 81  
     static Method findClosestMatchingMethod( Class<?> targetClass, Method m, String propertyName, Class<?> propertyType,
 82  
                                              boolean isReadMethod )
 83  
         throws OgnlException
 84  
     {
 85  3
         List<Method> methods = OgnlRuntime.getDeclaredMethods( targetClass, propertyName, !isReadMethod );
 86  
 
 87  3
         for ( Method method : methods )
 88  
         {
 89  4
             if ( method.getName().equals( m.getName() ) && m.getReturnType().isAssignableFrom( m.getReturnType() )
 90  
                 && method.getReturnType() == propertyType
 91  
                 && method.getParameterTypes().length == m.getParameterTypes().length )
 92  
             {
 93  1
                 return method;
 94  
             }
 95  
         }
 96  
 
 97  2
         return m;
 98  
     }
 99  
 
 100  
     private static void findObjectIndexedPropertyDescriptors( Class<?> targetClass,
 101  
                                                              Map<String, PropertyDescriptor> intoMap )
 102  
         throws OgnlException
 103  
     {
 104  83
         Map<String, List<Method>> allMethods = OgnlRuntime.getMethods( targetClass, false );
 105  83
         Map<String, List<Method>> pairs = new HashMap<String, List<Method>>( 101 );
 106  
 
 107  83
         for ( Map.Entry<String, List<Method>> entry : allMethods.entrySet() )
 108  
         {
 109  2251
             String methodName = entry.getKey();
 110  2251
             List<Method> methods = entry.getValue();
 111  
 
 112  
             /*
 113  
              * Only process set/get where there is exactly one implementation of the method per class and those
 114  
              * implementations are all the same
 115  
              */
 116  2251
             if ( indexMethodCheck( methods ) )
 117  
             {
 118  2104
                 boolean isGet = false, isSet;
 119  2104
                 Method method = methods.get( 0 );
 120  
 
 121  2104
                 if ( ( ( isSet = methodName.startsWith( OgnlRuntime.SET_PREFIX ) ) || ( isGet =
 122  
                     methodName.startsWith( OgnlRuntime.GET_PREFIX ) ) ) && ( methodName.length() > 3 ) )
 123  
                 {
 124  1055
                     String propertyName = Introspector.decapitalize( methodName.substring( 3 ) );
 125  1055
                     Class<?>[] parameterTypes = OgnlRuntime.getParameterTypes( method );
 126  1055
                     int parameterCount = parameterTypes.length;
 127  
 
 128  1055
                     if ( isGet && ( parameterCount == 1 ) && ( method.getReturnType() != Void.TYPE ) )
 129  
                     {
 130  82
                         List<Method> pair = pairs.get( propertyName );
 131  
 
 132  82
                         if ( pair == null )
 133  
                         {
 134  65
                             pairs.put( propertyName, pair = new ArrayList<Method>() );
 135  
                         }
 136  82
                         pair.add( method );
 137  
                     }
 138  1055
                     if ( isSet && ( parameterCount == 2 ) && ( method.getReturnType() == Void.TYPE ) )
 139  
                     {
 140  26
                         List<Method> pair = pairs.get( propertyName );
 141  
 
 142  26
                         if ( pair == null )
 143  
                         {
 144  20
                             pairs.put( propertyName, pair = new ArrayList<Method>() );
 145  
                         }
 146  26
                         pair.add( method );
 147  
                     }
 148  
                 }
 149  
             }
 150  2251
         }
 151  
 
 152  83
         for ( Map.Entry<String, List<Method>> entry : pairs.entrySet() )
 153  
         {
 154  85
             String propertyName = entry.getKey();
 155  85
             List<Method> methods = entry.getValue();
 156  
 
 157  85
             if ( methods.size() == 2 )
 158  
             {
 159  23
                 Method method1 = methods.get( 0 ), method2 = methods.get( 1 ), setMethod =
 160  23
                     ( method1.getParameterTypes().length == 2 ) ? method1 : method2, getMethod =
 161  
                     ( setMethod == method1 ) ? method2 : method1;
 162  23
                 Class<?> keyType = getMethod.getParameterTypes()[0], propertyType = getMethod.getReturnType();
 163  
 
 164  23
                 if ( keyType == setMethod.getParameterTypes()[0] )
 165  
                 {
 166  21
                     if ( propertyType == setMethod.getParameterTypes()[1] )
 167  
                     {
 168  
                         ObjectIndexedPropertyDescriptor propertyDescriptor;
 169  
 
 170  
                         try
 171  
                         {
 172  21
                             propertyDescriptor =
 173  
                                 new ObjectIndexedPropertyDescriptor( propertyName, propertyType, getMethod, setMethod );
 174  
                         }
 175  0
                         catch ( Exception ex )
 176  
                         {
 177  0
                             throw new OgnlException(
 178  
                                 "creating object indexed property descriptor for '" + propertyName + "' in "
 179  
                                     + targetClass, ex );
 180  21
                         }
 181  21
                         intoMap.put( propertyName, propertyDescriptor );
 182  
                     }
 183  
                 }
 184  
 
 185  
             }
 186  85
         }
 187  83
     }
 188  
     private static boolean indexMethodCheck( List<Method> methods )
 189  
     {
 190  2251
         boolean result = false;
 191  
 
 192  2251
         if ( methods.size() > 0 )
 193  
         {
 194  2251
             Method method = methods.get( 0 );
 195  2251
             Class<?>[] parameterTypes = OgnlRuntime.getParameterTypes( method );
 196  2251
             int numParameterTypes = parameterTypes.length;
 197  2251
             Class<?> lastMethodClass = method.getDeclaringClass();
 198  
 
 199  2251
             result = true;
 200  2577
             for ( int i = 1; result && ( i < methods.size() ); i++ )
 201  
             {
 202  326
                 Class<?> clazz = methods.get( i ).getDeclaringClass();
 203  
 
 204  
                 // Check to see if more than one method implemented per class
 205  326
                 if ( lastMethodClass == clazz )
 206  
                 {
 207  147
                     result = false;
 208  
                 }
 209  
                 else
 210  
                 {
 211  179
                     Class<?>[] mpt = OgnlRuntime.getParameterTypes( method );
 212  179
                     int mpc = parameterTypes.length;
 213  
 
 214  179
                     if ( numParameterTypes != mpc )
 215  
                     {
 216  0
                         result = false;
 217  
                     }
 218  282
                     for ( int j = 0; j < numParameterTypes; j++ )
 219  
                     {
 220  103
                         if ( parameterTypes[j] != mpt[j] )
 221  
                         {
 222  0
                             result = false;
 223  0
                             break;
 224  
                         }
 225  
                     }
 226  
                 }
 227  326
                 lastMethodClass = clazz;
 228  
             }
 229  
         }
 230  2251
         return result;
 231  
     }
 232  
 
 233  
 
 234  
 }