1 package org.apache.commons.ognl.internal.entry;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
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 public class PropertyDescriptorCacheEntryFactory
41 implements ClassCacheEntryFactory<Map<String, PropertyDescriptor>>
42 {
43 public Map<String, PropertyDescriptor> create( Class<?> targetClass )
44 throws CacheException
45 {
46 Map<String, PropertyDescriptor> result = new HashMap<String, PropertyDescriptor>( 101 );
47 PropertyDescriptor[] pda;
48 try
49 {
50 pda = Introspector.getBeanInfo( targetClass ).getPropertyDescriptors();
51
52 for (PropertyDescriptor aPda : pda) {
53
54 if (aPda.getReadMethod() != null && !OgnlRuntime.isMethodCallable(aPda.getReadMethod())) {
55 aPda.setReadMethod(
56 findClosestMatchingMethod(targetClass, aPda.getReadMethod(), aPda.getName(),
57 aPda.getPropertyType(), true));
58 }
59 if (aPda.getWriteMethod() != null && !OgnlRuntime.isMethodCallable(aPda.getWriteMethod())) {
60 aPda.setWriteMethod(
61 findClosestMatchingMethod(targetClass, aPda.getWriteMethod(), aPda.getName(),
62 aPda.getPropertyType(), false));
63 }
64
65 result.put(aPda.getName(), aPda);
66 }
67
68 findObjectIndexedPropertyDescriptors( targetClass, result );
69 }
70 catch ( IntrospectionException e )
71 {
72 throw new CacheException( e );
73 }
74 catch ( OgnlException e )
75 {
76 throw new CacheException( e );
77 }
78 return result;
79 }
80
81 static Method findClosestMatchingMethod( Class<?> targetClass, Method m, String propertyName, Class<?> propertyType,
82 boolean isReadMethod )
83 throws OgnlException
84 {
85 List<Method> methods = OgnlRuntime.getDeclaredMethods( targetClass, propertyName, !isReadMethod );
86
87 for ( Method method : methods )
88 {
89 if ( method.getName().equals( m.getName() ) && m.getReturnType().isAssignableFrom( m.getReturnType() )
90 && method.getReturnType() == propertyType
91 && method.getParameterTypes().length == m.getParameterTypes().length )
92 {
93 return method;
94 }
95 }
96
97 return m;
98 }
99
100 private static void findObjectIndexedPropertyDescriptors( Class<?> targetClass,
101 Map<String, PropertyDescriptor> intoMap )
102 throws OgnlException
103 {
104 Map<String, List<Method>> allMethods = OgnlRuntime.getMethods( targetClass, false );
105 Map<String, List<Method>> pairs = new HashMap<String, List<Method>>( 101 );
106
107 for ( Map.Entry<String, List<Method>> entry : allMethods.entrySet() )
108 {
109 String methodName = entry.getKey();
110 List<Method> methods = entry.getValue();
111
112
113
114
115
116 if ( indexMethodCheck( methods ) )
117 {
118 boolean isGet = false, isSet;
119 Method method = methods.get( 0 );
120
121 if ( ( ( isSet = methodName.startsWith( OgnlRuntime.SET_PREFIX ) ) || ( isGet =
122 methodName.startsWith( OgnlRuntime.GET_PREFIX ) ) ) && ( methodName.length() > 3 ) )
123 {
124 String propertyName = Introspector.decapitalize( methodName.substring( 3 ) );
125 Class<?>[] parameterTypes = OgnlRuntime.getParameterTypes( method );
126 int parameterCount = parameterTypes.length;
127
128 if ( isGet && ( parameterCount == 1 ) && ( method.getReturnType() != Void.TYPE ) )
129 {
130 List<Method> pair = pairs.get( propertyName );
131
132 if ( pair == null )
133 {
134 pairs.put( propertyName, pair = new ArrayList<Method>() );
135 }
136 pair.add( method );
137 }
138 if ( isSet && ( parameterCount == 2 ) && ( method.getReturnType() == Void.TYPE ) )
139 {
140 List<Method> pair = pairs.get( propertyName );
141
142 if ( pair == null )
143 {
144 pairs.put( propertyName, pair = new ArrayList<Method>() );
145 }
146 pair.add( method );
147 }
148 }
149 }
150 }
151
152 for ( Map.Entry<String, List<Method>> entry : pairs.entrySet() )
153 {
154 String propertyName = entry.getKey();
155 List<Method> methods = entry.getValue();
156
157 if ( methods.size() == 2 )
158 {
159 Method method1 = methods.get( 0 ), method2 = methods.get( 1 ), setMethod =
160 ( method1.getParameterTypes().length == 2 ) ? method1 : method2, getMethod =
161 ( setMethod == method1 ) ? method2 : method1;
162 Class<?> keyType = getMethod.getParameterTypes()[0], propertyType = getMethod.getReturnType();
163
164 if ( keyType == setMethod.getParameterTypes()[0] )
165 {
166 if ( propertyType == setMethod.getParameterTypes()[1] )
167 {
168 ObjectIndexedPropertyDescriptor propertyDescriptor;
169
170 try
171 {
172 propertyDescriptor =
173 new ObjectIndexedPropertyDescriptor( propertyName, propertyType, getMethod, setMethod );
174 }
175 catch ( Exception ex )
176 {
177 throw new OgnlException(
178 "creating object indexed property descriptor for '" + propertyName + "' in "
179 + targetClass, ex );
180 }
181 intoMap.put( propertyName, propertyDescriptor );
182 }
183 }
184
185 }
186 }
187 }
188 private static boolean indexMethodCheck( List<Method> methods )
189 {
190 boolean result = false;
191
192 if ( methods.size() > 0 )
193 {
194 Method method = methods.get( 0 );
195 Class<?>[] parameterTypes = OgnlRuntime.getParameterTypes( method );
196 int numParameterTypes = parameterTypes.length;
197 Class<?> lastMethodClass = method.getDeclaringClass();
198
199 result = true;
200 for ( int i = 1; result && ( i < methods.size() ); i++ )
201 {
202 Class<?> clazz = methods.get( i ).getDeclaringClass();
203
204
205 if ( lastMethodClass == clazz )
206 {
207 result = false;
208 }
209 else
210 {
211 Class<?>[] mpt = OgnlRuntime.getParameterTypes( method );
212 int mpc = parameterTypes.length;
213
214 if ( numParameterTypes != mpc )
215 {
216 result = false;
217 }
218 for ( int j = 0; j < numParameterTypes; j++ )
219 {
220 if ( parameterTypes[j] != mpt[j] )
221 {
222 result = false;
223 break;
224 }
225 }
226 }
227 lastMethodClass = clazz;
228 }
229 }
230 return result;
231 }
232
233
234 }