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.common; 017 018 import java.lang.reflect.Method; 019 import java.util.Iterator; 020 import java.util.Map; 021 022 import org.apache.commons.clazz.reflect.ReflectedClazz; 023 024 /** 025 * A ReflectedPropertyIntrospector that discovers list (aka indexed) properties. 026 * 027 * @author <a href="mailto:dmitri@apache.org">Dmitri Plotnikov</a> 028 * @version $Id: ReflectedListPropertyIntrospectorSupport.java 155436 2005-02-26 13:17:48Z dirkv $ 029 */ 030 public abstract class ReflectedListPropertyIntrospectorSupport 031 extends ReflectedPropertyIntrospectorSupport 032 { 033 protected static final AccessorMethodParser READ_METHOD_PARSER = 034 new ReadAccessorMethodParser(); 035 036 protected static final AccessorMethodParser WRITE_METHOD_PARSER = 037 new WriteAccessorMethodParser(); 038 039 protected static final AccessorMethodParser GET_METHOD_PARSER = 040 new GetAccessorMethodParser(); 041 042 protected static final AccessorMethodParser SET_METHOD_PARSER = 043 new SetAccessorMethodParser(); 044 045 protected AccessorMethodParser getReadAccessMethodParser() { 046 return READ_METHOD_PARSER; 047 } 048 049 protected AccessorMethodParser getWriteAccessMethodParser() { 050 return WRITE_METHOD_PARSER; 051 } 052 053 protected AccessorMethodParser getGetAccessMethodParser() { 054 return GET_METHOD_PARSER; 055 } 056 057 protected AccessorMethodParser getSetAccessMethodParser() { 058 return SET_METHOD_PARSER; 059 } 060 061 /** 062 * Finds a ReflectedListPropertyParseResults for the given 063 * propertyName or creates a new one and puts it in the map. 064 */ 065 protected ReflectedListPropertyParseResults getParseResults( 066 ReflectedClazz clazz, 067 Map parseResultMap, 068 String propertyName) 069 { 070 ReflectedListPropertyParseResults parseResults = 071 (ReflectedListPropertyParseResults) parseResultMap.get( 072 propertyName); 073 if (parseResults == null) { 074 parseResults = 075 new ReflectedListPropertyParseResults(clazz, propertyName); 076 parseResultMap.put(propertyName, parseResults); 077 } 078 return parseResults; 079 } 080 081 /** 082 * Combines data collected from singular methods like 083 * <code>getFoo(index)</code> with Properties, which already 084 * contain data about plural methods like <code>getFooList()</code>. 085 */ 086 protected void mergeSingularMethods( 087 Map parseResultMapPlural, Map parseResultMapSingular) 088 { 089 Iterator iter = parseResultMapSingular.values().iterator(); 090 while (iter.hasNext()) { 091 092 ReflectedListPropertyParseResults singular = 093 (ReflectedListPropertyParseResults) iter.next(); 094 095 ReflectedListPropertyParseResults plural = 096 findBySingularName( 097 parseResultMapPlural, singular.getPropertyName()); 098 099 if (plural != null) { 100 plural.merge(singular); 101 } 102 else { 103 // We don't have any plural methods - let's just use 104 // the singular ones then 105 parseResultMapPlural.put(singular.getPropertyName(), singular); 106 } 107 } 108 } 109 110 /** 111 * Given a singular form of a property name, locates parse results 112 * for a property with the corresponding plural name. 113 */ 114 protected ReflectedListPropertyParseResults findBySingularName( 115 Map parseResultMapPlural, 116 String singularName) 117 { 118 ReflectedListPropertyParseResults plural = 119 (ReflectedListPropertyParseResults) 120 parseResultMapPlural.get(singularName); 121 if (plural != null) { 122 return plural; 123 } 124 125 Iterator iter = parseResultMapPlural.entrySet().iterator(); 126 while (iter.hasNext()) { 127 Map.Entry entry = (Map.Entry) iter.next(); 128 if (isCorrectPluralForm(singularName, (String) entry.getKey())) { 129 return (ReflectedListPropertyParseResults) entry.getValue(); 130 } 131 } 132 return null; 133 } 134 135 /** 136 * Creates a new ReflectedListProperty based on parse results. 137 */ 138 protected ReflectedAccessorPairProperty createProperty( 139 ReflectedClazz clazz, 140 ReflectedPropertyParseResults parseResults) 141 { 142 ReflectedListProperty property = 143 new ReflectedListProperty(clazz, parseResults.getPropertyName()); 144 145 ReflectedListPropertyParseResults parseResultsList = 146 (ReflectedListPropertyParseResults) parseResults; 147 148 property.setAliases(parseResultsList.getAliases()); 149 property.setType(parseResultsList.getPropertyType()); 150 property.setContentType(parseResultsList.getContentType()); 151 property.setReadMethod(parseResultsList.getReadMethod()); 152 property.setWriteMethod(parseResultsList.getWriteMethod()); 153 property.setGetMethod(parseResultsList.getGetMethod()); 154 property.setSetMethod(parseResultsList.getSetMethod()); 155 property.setAddMethod(parseResultsList.getAddMethod()); 156 property.setAddIndexedMethod(parseResultsList.getAddIndexedMethod()); 157 property.setRemoveMethod(parseResultsList.getRemoveMethod()); 158 property.setRemoveIndexedMethod( 159 parseResultsList.getRemoveIndexedMethod()); 160 property.setSizeMethod(parseResultsList.getSizeMethod()); 161 return property; 162 } 163 /** 164 * Parser for the <code>getFooMap()</code> method: 165 * <ul> 166 * <li>Return type not void</li> 167 * <li>Name starts with "get" followed by capitalized property name</li> 168 * <li>No parameters</li> 169 * </ul> 170 * 171 * We don't check if the parameter is a List here. If it is not, 172 * we want to recognize the method and them mark the corresponding 173 * property as NotAProperty. 174 */ 175 public static class ReadAccessorMethodParser extends AccessorMethodParser { 176 protected boolean testReturnType(Class returnType) { 177 return !returnType.equals(Void.TYPE); 178 } 179 protected String requiredPrefix() { 180 return "get"; 181 } 182 protected int requiredParameterCount() { 183 return 0; 184 } 185 protected Class getValueType(Method method) { 186 return method.getReturnType(); 187 } 188 } 189 190 /** 191 * Parser for the <code>setFooList(List)</code> method: 192 * <ul> 193 * <li>Return type void</li> 194 * <li>Name starts with "set" followed by capitalized property name</li> 195 * <li>One parameter</li> 196 * </ul> 197 * 198 * We don't check if the parameter is a List here. If it is not, 199 * we want to recognize the method and them mark the corresponding 200 * property as NotAProperty. 201 */ 202 public static class WriteAccessorMethodParser extends AccessorMethodParser { 203 protected boolean testReturnType(Class returnType) { 204 return returnType.equals(Void.TYPE); 205 } 206 protected int requiredParameterCount() { 207 return 1; 208 } 209 protected String requiredPrefix() { 210 return "set"; 211 } 212 protected Class getValueType(Method method) { 213 return method.getParameterTypes()[0]; 214 } 215 } 216 217 /** 218 * Parser for the <code>getFoo(int)</code> method: 219 * <ul> 220 * <li>Return type not void</li> 221 * <li>Name starts with "get" followed by capitalized singular 222 * form of the property name</li> 223 * <li>One integer parameter</li> 224 * </ul> 225 */ 226 public static class GetAccessorMethodParser extends AccessorMethodParser { 227 protected boolean testReturnType(Class returnType) { 228 return !returnType.equals(Void.TYPE); 229 } 230 protected String requiredPrefix() { 231 return "get"; 232 } 233 protected int requiredParameterCount() { 234 return 1; 235 } 236 protected boolean testParameterType(int index, Class parameterType) { 237 return parameterType.equals(Integer.TYPE); 238 } 239 protected Class getValueType(Method method) { 240 return method.getReturnType(); 241 } 242 } 243 244 /** 245 * Parser for the <code>setFoo(index, value)</code> method: 246 * <ul> 247 * <li>Return type void</li> 248 * <li>Name starts with "set" followed by capitalized singular 249 * form of the property name</li> 250 * <li>Two parameters, first integer</li> 251 * </ul> 252 */ 253 public static class SetAccessorMethodParser extends AccessorMethodParser { 254 protected String requiredPrefix() { 255 return "set"; 256 } 257 protected int requiredParameterCount() { 258 return 2; 259 } 260 protected boolean testParameterType(int index, Class parameterType) { 261 if (index == 0) { 262 return parameterType.equals(Integer.TYPE); 263 } 264 return true; 265 } 266 protected Class getValueType(Method method) { 267 return method.getParameterTypes()[1]; 268 } 269 } 270 271 }