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 }