001 /*
002 * Copyright 2002-2004 The Apache Software Foundation
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 * http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 */
016 package org.apache.commons.clazz.reflect.extended;
017
018 import java.lang.reflect.Method;
019 import java.util.HashMap;
020 import java.util.Iterator;
021 import java.util.Map;
022
023 import org.apache.commons.clazz.reflect.ReflectedClazz;
024 import org.apache.commons.clazz.reflect.common.*;
025
026 /**
027 * A ReflectedPropertyIntrospector that discovers list (aka indexed) properties.
028 *
029 * @author <a href="mailto:dmitri@apache.org">Dmitri Plotnikov</a>
030 * @version $Id: ExtendedReflectedListPropertyIntrospector.java 155436 2005-02-26 13:17:48Z dirkv $
031 */
032 public class ExtendedReflectedListPropertyIntrospector
033 extends ReflectedListPropertyIntrospectorSupport
034 {
035 protected static final AccessorMethodParser ADD_METHOD_PARSER =
036 new AddAccessorMethodParser();
037
038 protected static final AccessorMethodParser ADD_INDEXED_METHOD_PARSER =
039 new AddIndexedAccessorMethodParser();
040
041 protected static final AccessorMethodParser REMOVE_INDEXED_METHOD_PARSER =
042 new RemoveIndexedAccessorMethodParser();
043
044 protected static final AccessorMethodParser REMOVE_METHOD_PARSER =
045 new RemoveAccessorMethodParser();
046
047 protected static final AccessorMethodParser SIZE_METHOD_PARSER =
048 new SizeAccessorMethodParser();
049
050
051 public void introspectProperties(
052 ReflectedClazz clazz,
053 Class javaClass,
054 Map parseResultMap)
055 {
056 HashMap parseResultMapSingular = new HashMap();
057 Method methods[] = javaClass.getMethods();
058 ReflectedListPropertyParseResults parseResults;
059 AccessorMethodParseResults results;
060 for (int i = 0; i < methods.length; i++) {
061 Method method = methods[i];
062 Method method3 = method;
063
064 // Check getFooCount() before we check getFooList(),
065 // because the parser for the latter is generic enough
066 // to include the former
067 results = getSizeAccessorMethodParser().parse(method3);
068 if (results != null) {
069 parseResults =
070 getParseResults(
071 clazz,
072 parseResultMapSingular,
073 results.getPropertyName());
074 parseResults.setSizeMethodParseResults(results);
075 continue;
076 }
077
078 results = getReadAccessMethodParser().parse(method);
079 if (results != null) {
080 parseResults =
081 getParseResults(
082 clazz,
083 parseResultMap,
084 results.getPropertyName());
085 parseResults.setReadMethodParseResults(results);
086 continue;
087 }
088
089 results = getWriteAccessMethodParser().parse(method);
090 if (results != null) {
091 parseResults =
092 getParseResults(
093 clazz,
094 parseResultMap,
095 results.getPropertyName());
096 parseResults.setWriteMethodParseResults(results);
097 continue;
098 }
099
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 }