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 }