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.common;
17  
18  import java.lang.reflect.Method;
19  import java.util.Map;
20  
21  import org.apache.commons.clazz.reflect.ReflectedClazz;
22  
23  /**
24   * A ReflectedPropertyIntrospector that discovers scalar properties.
25   * 
26   * @author <a href="mailto:dmitri@apache.org">Dmitri Plotnikov</a>
27   * @version $Id: ReflectedScalarPropertyIntrospector.java 155436 2005-02-26 13:17:48Z dirkv $
28   */
29  public class ReflectedScalarPropertyIntrospector 
30              extends ReflectedPropertyIntrospectorSupport 
31  {
32      protected static final AccessorMethodParser READ_METHOD_PARSER =
33          new JBReadAccessorMethodParser();
34  
35      protected static final AccessorMethodParser WRITE_METHOD_PARSER =
36          new WriteAccessorMethodParser();
37     
38      public void introspectProperties(
39              ReflectedClazz clazz,
40              Class javaClass,
41              Map parseResultMap)
42      {
43          Method methods[] = javaClass.getMethods();
44          ReflectedScalarPropertyParseResults parseResults;
45          AccessorMethodParseResults results;
46          for (int i = 0; i < methods.length; i++) {
47              Method method = methods[i];
48              if (method.getDeclaringClass().equals(Object.class)) {
49                  continue;
50              }
51              
52              results = getReadAccessorMethodParser().parse(method);
53              if (results != null) {
54                  parseResults =
55                      getParseResults(
56                          clazz,
57                          parseResultMap,
58                          results.getPropertyName());
59                  parseResults.setReadMethodParseResults(results);
60                  continue;
61              }
62              
63              results = getWriteAccessorMethodParser().parse(method);
64              if (results != null) {
65                  parseResults =
66                      getParseResults(
67                          clazz,
68                          parseResultMap,
69                          results.getPropertyName());
70                  parseResults.setWriteMethodParseResults(results);
71                  continue;
72              }    
73          }
74      }
75   
76      /**
77       * Override to return an alternative parser for the read accessor method.
78       */
79      protected AccessorMethodParser getReadAccessorMethodParser() {
80          return READ_METHOD_PARSER;
81      }
82      
83      protected AccessorMethodParser getWriteAccessorMethodParser() {
84          return WRITE_METHOD_PARSER;
85      }    
86  
87      /**
88       * Finds a ReflectedScalarPropertyParseResults for the given
89       * propertyName or creates a new one and puts it in the map.
90       */
91      protected ReflectedScalarPropertyParseResults getParseResults(
92              ReflectedClazz clazz,
93              Map parseResultMap,
94              String propertyName) 
95      {
96          ReflectedScalarPropertyParseResults parseResults =
97              (ReflectedScalarPropertyParseResults) parseResultMap.get(
98                  propertyName);
99          if (parseResults == null) {
100             parseResults =
101                 new ReflectedScalarPropertyParseResults(clazz, propertyName);
102             parseResultMap.put(propertyName, parseResults);
103         }
104         return parseResults;
105     }
106     
107     /**
108      * Creates a new ReflectedAccessorPairProperty based on parse results. 
109      */
110     protected ReflectedAccessorPairProperty createProperty(
111         ReflectedClazz clazz,
112         ReflectedPropertyParseResults parseResults)
113     {
114         ReflectedScalarProperty property =
115             new ReflectedScalarProperty(clazz, parseResults.getPropertyName());
116 
117         property.setType(parseResults.getPropertyType());
118         property.setReadMethod(parseResults.getReadMethod());
119         property.setWriteMethod(parseResults.getWriteMethod());
120         return property;
121     }
122 
123     /**
124      * Parser for the <code>getFoo()</code> method:
125      * <ul>
126      *  <li>Return type not void</li>
127      *  <li>Name starts with "get" followed by capitalized property name.
128      *  <li>No parameters</li>
129      * </ul>
130      */
131     public static class ReadAccessorMethodParser extends AccessorMethodParser {
132         protected boolean testReturnType(Class returnType) {
133             return !returnType.equals(Void.TYPE);
134         }
135         protected int requiredParameterCount() {
136             return 0;
137         }
138         protected String requiredPrefix() {
139             return "get";
140         }
141         protected Class getValueType(Method method) {
142             return method.getReturnType();
143         }
144     }
145                    
146     /**
147      * Parser for the <code>getFoo()</code> method:
148      * <ul>
149      *  <li>Return type not void</li>
150      *  <li>Name starts with "get" followed by capitalized property name.
151      *      If the property is boolean the name may also start with "is".</li>
152      *  <li>No parameters</li>
153      * </ul>
154      */
155     public static class JBReadAccessorMethodParser 
156             extends ReadAccessorMethodParser
157     {               
158         protected String getPropertyName(Method method) {
159             String name = method.getName();
160             String propertyName = null;
161             if (name.startsWith("get")) {
162                 if (name.length() <= 3) {
163                     return null;
164                 }
165                 if (!testFirstCharacterOfPropertyName(name.charAt(3))) {
166                     return null;
167                 }
168                 propertyName = decapitalize(name.substring(3));
169             }
170             else if (method.getReturnType().equals(Boolean.TYPE)
171                     && name.startsWith("is")) {
172                 if (name.length() <= 2) {
173                     return null;
174                 }
175                 if (!testFirstCharacterOfPropertyName(name.charAt(2))) {
176                     return null;
177                 }
178                 propertyName = decapitalize(name.substring(2));
179             }
180             return propertyName;
181         }
182     };
183             
184     /**
185      * Parser for the <code>setFoo(value)</code> method:
186      * <ul>
187      *  <li>Return type void</li>
188      *  <li>Name starts with "set" followed by capitalized property name</li>
189      *  <li>One parameter</li>
190      * </ul>
191      */            
192     public static class WriteAccessorMethodParser extends AccessorMethodParser {
193         protected int requiredParameterCount() {
194             return 1;
195         }
196         protected String requiredPrefix() {
197             return "set";
198         }
199         protected boolean testReturnType(Class returnType) {
200             return returnType.equals(Void.TYPE);
201         }
202         protected Class getValueType(Method method) {
203             return method.getParameterTypes()[0];
204         }
205     }
206 
207 }