View Javadoc

1   /*
2    * Copyright 2002-2004 The Apache Software Foundation
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   */
16  package org.apache.commons.clazz.reflect.extended;
17  
18  import java.lang.reflect.Method;
19  import java.util.HashMap;
20  import java.util.Iterator;
21  import java.util.Map;
22  
23  import org.apache.commons.clazz.reflect.ReflectedClazz;
24  import org.apache.commons.clazz.reflect.common.*;
25  
26  /**
27   * A ReflectedPropertyIntrospector that discovers list (aka indexed) properties.
28   * 
29   * @author <a href="mailto:dmitri@apache.org">Dmitri Plotnikov</a>
30   * @version $Id: ExtendedReflectedListPropertyIntrospector.java 155436 2005-02-26 13:17:48Z dirkv $
31   */
32  public class ExtendedReflectedListPropertyIntrospector
33      extends ReflectedListPropertyIntrospectorSupport 
34  {
35      protected static final AccessorMethodParser ADD_METHOD_PARSER =
36          new AddAccessorMethodParser();
37  
38      protected static final AccessorMethodParser ADD_INDEXED_METHOD_PARSER =
39          new AddIndexedAccessorMethodParser();
40  
41      protected static final AccessorMethodParser REMOVE_INDEXED_METHOD_PARSER =
42          new RemoveIndexedAccessorMethodParser();
43  
44      protected static final AccessorMethodParser REMOVE_METHOD_PARSER =
45          new RemoveAccessorMethodParser();
46  
47      protected static final AccessorMethodParser SIZE_METHOD_PARSER =
48          new SizeAccessorMethodParser();
49                          
50                             
51      public void introspectProperties(
52              ReflectedClazz clazz,
53              Class javaClass,
54              Map parseResultMap)
55      {
56          HashMap parseResultMapSingular = new HashMap();
57          Method methods[] = javaClass.getMethods();
58          ReflectedListPropertyParseResults parseResults;
59          AccessorMethodParseResults results;
60          for (int i = 0; i < methods.length; i++) {
61              Method method = methods[i];
62              Method method3 = method;
63  
64              // Check getFooCount() before we check getFooList(),
65              // because the parser for the latter is generic enough
66              // to include the former            
67              results = getSizeAccessorMethodParser().parse(method3);
68              if (results != null) {
69                  parseResults =
70                      getParseResults(
71                          clazz,
72                          parseResultMapSingular,
73                          results.getPropertyName());
74                  parseResults.setSizeMethodParseResults(results);
75                  continue;
76              }
77              
78              results = getReadAccessMethodParser().parse(method);
79              if (results != null) {
80                  parseResults =
81                      getParseResults(
82                          clazz,
83                          parseResultMap,
84                          results.getPropertyName());
85                  parseResults.setReadMethodParseResults(results);
86                  continue;
87              }
88  
89              results = getWriteAccessMethodParser().parse(method);
90              if (results != null) {
91                  parseResults =
92                      getParseResults(
93                          clazz,
94                          parseResultMap,
95                          results.getPropertyName());
96                  parseResults.setWriteMethodParseResults(results);
97                  continue;
98              }
99  
100             results = getGetAccessMethodParser().parse(method);
101             if (results != null) {
102                 parseResults =
103                     getParseResults(
104                         clazz,
105                         parseResultMapSingular,
106                         results.getPropertyName());
107                 parseResults.setGetMethodParseResults(results);
108                 continue;
109             }
110             
111             results = getSetAccessMethodParser().parse(method);
112             if (results != null) {
113                 parseResults =
114                     getParseResults(
115                         clazz,
116                         parseResultMapSingular,
117                         results.getPropertyName());
118                 parseResults.setSetMethodParseResults(results);
119                 continue;
120             }
121             
122             results = getAddAccessorMethodParser().parse(method);
123             if (results != null) {
124                 parseResults =
125                     getParseResults(
126                         clazz,
127                         parseResultMapSingular,
128                         results.getPropertyName());
129                 parseResults.setAddMethodParseResults(results);
130                 continue;
131             }
132 
133             results = getAddIndexedAccessorMethodParser().parse(method);
134             if (results != null) {
135                 parseResults =
136                     getParseResults(
137                         clazz,
138                         parseResultMapSingular,
139                         results.getPropertyName());
140                 parseResults.setAddIndexedMethodParseResults(results);
141                 continue;
142             }
143 
144             results = getRemoveAccessorMethodParser().parse(method);
145             if (results != null) {
146                 parseResults =
147                     getParseResults(
148                         clazz,
149                         parseResultMapSingular,
150                         results.getPropertyName());
151                 parseResults.setRemoveMethodParseResults(results);
152                 continue;
153             }
154 
155             results = getRemoveIndexedAccessorMethodParser().parse(method);
156             if (results != null) {
157                 parseResults =
158                     getParseResults(
159                         clazz,
160                         parseResultMapSingular,
161                         results.getPropertyName());
162                 parseResults.setRemoveIndexedMethodParseResults(results);
163                 continue;
164             }
165         }
166         
167         Iterator iter = parseResultMap.entrySet().iterator();
168         while (iter.hasNext()) {
169             Map.Entry entry = (Map.Entry) iter.next();
170             ReflectedListPropertyParseResults result = 
171                 (ReflectedListPropertyParseResults) entry.getValue();
172             if (!result.isList()) {
173                 iter.remove();
174             }
175         }
176         
177         mergeSingularMethods(parseResultMap, parseResultMapSingular);
178     }
179     
180     protected AccessorMethodParser getAddAccessorMethodParser() {
181         return ADD_METHOD_PARSER;
182     }
183 
184     protected AccessorMethodParser getAddIndexedAccessorMethodParser() {
185         return ADD_INDEXED_METHOD_PARSER;
186     }
187 
188     protected AccessorMethodParser getRemoveAccessorMethodParser() {
189         return REMOVE_METHOD_PARSER;
190     }
191 
192     protected AccessorMethodParser getRemoveIndexedAccessorMethodParser() {
193         return REMOVE_INDEXED_METHOD_PARSER;
194     }
195 
196     protected AccessorMethodParser getSizeAccessorMethodParser() {
197         return SIZE_METHOD_PARSER;
198     }
199 
200     /**
201      * Returns <code>true</code> if the suffix is "s" or 
202      * "List", "Array" or "Vector".
203      *  
204      * @see ReflectedPropertyIntrospectorSupport#isCorrectPluralSuffix(String,String)
205      */
206     protected boolean isCorrectPluralSuffix(String singular, String suffix) {
207         return super.isCorrectPluralSuffix(singular, suffix)
208             || suffix.equals("List")
209             || suffix.equals("Array")
210             || suffix.equals("Vector");
211     }
212 
213     /**
214      * Parser for the <code>addFoo(value)</code> method:
215      * <ul>
216      *  <li>Return type void</li>
217      *  <li>Name starts with "add" followed by capitalized singular
218      *      form of the property name</li>
219      *  <li>One parameter</li>
220      * </ul>
221      */                        
222     public static class AddAccessorMethodParser extends AccessorMethodParser {
223         protected String requiredPrefix() {
224             return "add";
225         }
226         protected int requiredParameterCount() {
227             return 1;
228         }
229         protected Class getValueType(Method method) {
230             return method.getParameterTypes()[0];
231         }
232     }
233     
234     /**
235      * Parser for the <code>addFoo(index, value)</code> method:
236      * <ul>
237      *  <li>Return type void</li>
238      *  <li>Name starts with "add" followed by capitalized singular
239      *      form of the property name</li>
240      *  <li>Two parameters, first integer</li>
241      * </ul>
242      */                        
243     public static class AddIndexedAccessorMethodParser
244         extends AccessorMethodParser 
245     {
246         protected String requiredPrefix() {
247             return "add";
248         }
249         protected int requiredParameterCount() {
250             return 2;
251         }
252         protected boolean testParameterType(int index, Class parameterType) {
253             if (index == 0) {
254                 return parameterType.equals(Integer.TYPE);
255             }
256             return true;
257         }
258         protected Class getValueType(Method method) {
259             return method.getParameterTypes()[1];
260         }
261     }
262         
263     /**
264      * Parser for the <code>removeFoo(index)</code> method:
265      * <ul>
266      *  <li>Name starts with "remove" followed by capitalized singular
267      *      form of the property name</li>
268      *  <li>One integer parameter</li>
269      * </ul>
270      */
271     public static class RemoveIndexedAccessorMethodParser
272         extends AccessorMethodParser 
273     {
274         protected String requiredPrefix() {
275             return "remove";
276         }
277         protected int requiredParameterCount() {
278             return 1;
279         }
280         protected boolean testParameterType(int index, Class parameterType) {
281             return parameterType.equals(Integer.TYPE);
282         }
283     }
284 
285     /**
286      * Parser for the <code>removeFoo(value)</code> method:
287      * <ul>
288      *  <li>Name starts with "remove" followed by capitalized singular
289      *      form of the property name</li>
290      *  <li>One parameter</li>
291      * </ul>
292      */                        
293     public static class RemoveAccessorMethodParser 
294         extends AccessorMethodParser 
295     {
296         protected String requiredPrefix() {
297             return "remove";
298         }
299         protected int requiredParameterCount() {
300             return 1;
301         }
302         protected boolean testParameterType(int index, Class parameterType) {
303             return !parameterType.equals(Integer.TYPE);
304         }
305         protected Class getValueType(Method method) {
306             return method.getParameterTypes()[0];
307         }
308     }
309     
310     /**
311      * Parser for the <code>getFooCount()</code> method:
312      * <ul>
313      *  <li>Returns integer</li>
314      *  <li>Name starts with "get" followed by capitalized singular
315      *      form of the property name, followed by "Count" or "Size"</li>
316      *  <li>No parameters</li>
317      * </ul>
318      */                        
319     public static class SizeAccessorMethodParser extends AccessorMethodParser {
320         protected boolean testReturnType(Class javaClass) {
321             return javaClass.equals(Integer.TYPE);
322         }
323         protected String requiredPrefix() {
324             return "get";
325         }
326         protected int requiredParameterCount() {
327             return 0;
328         }
329         protected String testAndRemoveSuffix(String methodName) {
330             if (methodName.endsWith("Count")) {                
331                 return methodName.substring(0, methodName.length() - 5);
332             }
333             if (methodName.endsWith("Size")) {
334                 return methodName.substring(0, methodName.length() - 4);
335             }
336             return null;
337         }
338     }
339             
340 }