Coverage Report - org.apache.commons.clazz.reflect.extended.ReflectedMappedPropertyIntrospector
 
Classes in this File Line Coverage Branch Coverage Complexity
ReflectedMappedPropertyIntrospector
0%
0/96
0%
0/34
1.622
ReflectedMappedPropertyIntrospector$GetAccessorMethodParser
0%
0/6
0%
0/2
1.622
ReflectedMappedPropertyIntrospector$KeySetAccessorMethodParser
0%
0/9
0%
0/10
1.622
ReflectedMappedPropertyIntrospector$PutAccessorMethodParser
0%
0/5
N/A
1.622
ReflectedMappedPropertyIntrospector$ReadAccessorMethodParser
0%
0/5
0%
0/2
1.622
ReflectedMappedPropertyIntrospector$RemoveAccessorMethodParser
0%
0/8
0%
0/2
1.622
ReflectedMappedPropertyIntrospector$WriteAccessorMethodParser
0%
0/5
N/A
1.622
 
 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.extended;
 17  
 
 18  
 import java.lang.reflect.Method;
 19  
 import java.util.Collection;
 20  
 import java.util.HashMap;
 21  
 import java.util.Iterator;
 22  
 import java.util.Map;
 23  
 
 24  
 import org.apache.commons.clazz.reflect.ReflectedClazz;
 25  
 import org.apache.commons.clazz.reflect.common.*;
 26  
 
 27  
 /**
 28  
  * A ReflectedPropertyIntrospector that discovers mapped properties.
 29  
  * 
 30  
  * @author <a href="mailto:dmitri@apache.org">Dmitri Plotnikov</a>
 31  
  * @version $Id: ReflectedMappedPropertyIntrospector.java 155436 2005-02-26 13:17:48Z dirkv $
 32  
  */
 33  0
 public class ReflectedMappedPropertyIntrospector
 34  
     extends ReflectedPropertyIntrospectorSupport 
 35  
 {
 36  0
     protected static final AccessorMethodParser READ_METHOD_PARSER =
 37  
         new ReadAccessorMethodParser();
 38  
 
 39  0
     protected static final AccessorMethodParser WRITE_METHOD_PARSER =
 40  
         new WriteAccessorMethodParser();
 41  
 
 42  0
     protected static final AccessorMethodParser GET_METHOD_PARSER =
 43  
         new GetAccessorMethodParser();
 44  
 
 45  0
     protected static final AccessorMethodParser PUT_METHOD_PARSER =
 46  
         new PutAccessorMethodParser();
 47  
 
 48  0
     protected static final AccessorMethodParser REMOVE_METHOD_PARSER =
 49  
         new RemoveAccessorMethodParser();
 50  
 
 51  0
     protected static final AccessorMethodParser KEY_SET_METHOD_PARSER =
 52  
         new KeySetAccessorMethodParser();
 53  
                                     
 54  
     /**
 55  
      * Goes over methods of the supplied class and creates 
 56  
      * ReflectedAccessorPairProperty objects for discovered properties.
 57  
      */
 58  
     public void introspectProperties(
 59  
             ReflectedClazz clazz,
 60  
             Class javaClass,
 61  
             Map parseResultMap)
 62  
     {
 63  0
         HashMap parseResultMapSingular = new HashMap();
 64  0
         Method methods[] = javaClass.getMethods();
 65  
         ReflectedMappedPropertyParseResults parseResults;
 66  
         AccessorMethodParseResults results;
 67  0
         for (int i = 0; i < methods.length; i++) {
 68  0
             Method method = methods[i];
 69  
             
 70  
             // Check getFooKeys() before we check getFooList(),
 71  
             // because the parser for the latter is generic enough
 72  
             // to include the former            
 73  0
             results = getKeySetAccessorMethodParser().parse(method);
 74  0
             if (results != null) {
 75  0
                 parseResults =
 76  
                     getParseResults(
 77  
                         clazz,
 78  
                         parseResultMapSingular,
 79  
                         results.getPropertyName());
 80  0
                 parseResults.setKeySetMethodParseResults(results);
 81  0
                 continue;
 82  
             }
 83  
 
 84  0
             results = getReadAccessorMethodParser().parse(method);
 85  0
             if (results != null) {
 86  0
                 parseResults =
 87  
                     getParseResults(
 88  
                         clazz,
 89  
                         parseResultMap,
 90  
                         results.getPropertyName());
 91  0
                 parseResults.setReadMethodParseResults(results);
 92  0
                 continue;
 93  
             }
 94  
 
 95  0
             results = getWriteAccessorMethodParser().parse(method);
 96  0
             if (results != null) {
 97  0
                 parseResults =
 98  
                     getParseResults(
 99  
                         clazz,
 100  
                         parseResultMap,
 101  
                         results.getPropertyName());
 102  0
                 parseResults.setWriteMethodParseResults(results);
 103  0
                 continue;
 104  
             }
 105  
 
 106  0
             results = getGetAccessorMethodParser().parse(method);
 107  0
             if (results != null) {
 108  0
                 parseResults =
 109  
                     getParseResults(
 110  
                         clazz,
 111  
                         parseResultMapSingular,
 112  
                         results.getPropertyName());
 113  0
                 parseResults.setGetMethodParseResults(results);
 114  0
                 continue;
 115  
             }
 116  
 
 117  0
             results = getPutAccessorMethodParser().parse(method);
 118  0
             if (results != null) {
 119  0
                 parseResults =
 120  
                     getParseResults(
 121  
                         clazz,
 122  
                         parseResultMapSingular,
 123  
                         results.getPropertyName());
 124  0
                 parseResults.setPutMethodParseResults(results);
 125  0
                 continue;
 126  
             }
 127  
             
 128  0
             results = getRemoveAccessorMethodParser().parse(method);
 129  0
             if (results != null) {
 130  0
                 parseResults =
 131  
                     getParseResults(
 132  
                         clazz,
 133  
                         parseResultMapSingular,
 134  
                         results.getPropertyName());
 135  0
                 parseResults.setRemoveMethodParseResults(results);
 136  0
                 continue;
 137  
             }
 138  
         }
 139  
         
 140  0
         Iterator iter = parseResultMap.entrySet().iterator();
 141  0
         while (iter.hasNext()) {
 142  0
             Map.Entry entry = (Map.Entry) iter.next();
 143  0
             ReflectedMappedPropertyParseResults result = 
 144  
                 (ReflectedMappedPropertyParseResults) entry.getValue();
 145  0
             if (!result.isMap()) {
 146  0
                 iter.remove();
 147  
             }
 148  0
         }
 149  
         
 150  0
         mergeSingularMethods(parseResultMap, parseResultMapSingular);
 151  0
     }
 152  
 
 153  
     protected AccessorMethodParser getReadAccessorMethodParser() {
 154  0
         return READ_METHOD_PARSER;
 155  
     }
 156  
     
 157  
     protected AccessorMethodParser getWriteAccessorMethodParser() {
 158  0
         return WRITE_METHOD_PARSER;
 159  
     }
 160  
     
 161  
     protected AccessorMethodParser getGetAccessorMethodParser() {
 162  0
         return GET_METHOD_PARSER;
 163  
     }
 164  
     
 165  
     protected AccessorMethodParser getPutAccessorMethodParser() {
 166  0
         return PUT_METHOD_PARSER;
 167  
     }
 168  
     
 169  
     protected AccessorMethodParser getRemoveAccessorMethodParser() {
 170  0
         return REMOVE_METHOD_PARSER;
 171  
     }
 172  
     
 173  
     protected AccessorMethodParser getKeySetAccessorMethodParser() {
 174  0
         return KEY_SET_METHOD_PARSER;
 175  
     }
 176  
 
 177  
     /**
 178  
      * Combines data collected from singular methods like 
 179  
      * <code>getFoo(key)</code> with parse results for plural methods 
 180  
      * like <code>getFooMap()</code>. 
 181  
      */    
 182  
     protected void mergeSingularMethods(
 183  
             Map parseResultMapPlural, Map parseResultMapSingular)
 184  
     {
 185  0
         Iterator iter = parseResultMapSingular.values().iterator();
 186  0
         while (iter.hasNext()) {
 187  
             
 188  0
             ReflectedMappedPropertyParseResults singular =
 189  
                 (ReflectedMappedPropertyParseResults) iter.next();
 190  
                 
 191  0
             ReflectedMappedPropertyParseResults plural =
 192  
                 findBySingularName(
 193  
                         parseResultMapPlural, singular.getPropertyName());
 194  
             
 195  0
             if (plural != null) {
 196  0
                 plural.merge(singular);
 197  
             }
 198  
             else {
 199  
                 // We don't have any plural methods - let's just use
 200  
                 // the singular ones then
 201  0
                 parseResultMapPlural.put(singular.getPropertyName(), singular);
 202  
             }
 203  0
         }
 204  0
     }
 205  
 
 206  
     /**
 207  
      * Given a singular form of a property name, locates parse results
 208  
      * for a property with the corresponding plural name.
 209  
      */
 210  
     protected ReflectedMappedPropertyParseResults findBySingularName(
 211  
             Map parseResultMapPlural,
 212  
             String singularName) 
 213  
     {
 214  0
         ReflectedMappedPropertyParseResults plural =
 215  
             (ReflectedMappedPropertyParseResults) 
 216  
                 parseResultMapPlural.get(singularName);
 217  0
         if (plural != null) {
 218  0
             return plural;
 219  
         }
 220  
 
 221  0
         Iterator iter = parseResultMapPlural.entrySet().iterator();
 222  0
         while (iter.hasNext()) {
 223  0
             Map.Entry entry = (Map.Entry) iter.next();
 224  0
             if (isCorrectPluralForm(singularName, (String) entry.getKey())) {
 225  0
                 return (ReflectedMappedPropertyParseResults) entry.getValue();
 226  
             }
 227  0
         }
 228  0
         return null;
 229  
     }
 230  
 
 231  
     /**
 232  
      * Returns <code>true</code> if the suffix is "s" or "Map".
 233  
      *  
 234  
      * @see ReflectedPropertyIntrospectorSupport#isCorrectPluralSuffix(String,String)
 235  
      */
 236  
     protected boolean isCorrectPluralSuffix(String singular, String suffix) {
 237  0
         return super.isCorrectPluralSuffix(singular, suffix)
 238  
             || suffix.equals("Map");
 239  
     }
 240  
     
 241  
      
 242  
     /**
 243  
      * Finds a ReflectedMappedPropertyParseResults for the given
 244  
      * propertyName or creates a new one and puts it in the map.
 245  
      */
 246  
     protected ReflectedMappedPropertyParseResults getParseResults(
 247  
             ReflectedClazz clazz,
 248  
             Map parseResultMap,
 249  
             String propertyName) 
 250  
     {
 251  0
         ReflectedMappedPropertyParseResults parseResults =
 252  
             (ReflectedMappedPropertyParseResults) parseResultMap.get(
 253  
                 propertyName);
 254  0
         if (parseResults == null) {
 255  0
             parseResults =
 256  
                 new ReflectedMappedPropertyParseResults(clazz, propertyName);
 257  0
             parseResultMap.put(propertyName, parseResults);
 258  
         }
 259  0
         return parseResults;
 260  
     }
 261  
     
 262  
     /**
 263  
      * Creates a new ReflectedMappedProperty based on parse results. 
 264  
      */
 265  
     protected ReflectedAccessorPairProperty createProperty(
 266  
         ReflectedClazz clazz,
 267  
         ReflectedPropertyParseResults parseResults)
 268  
     {
 269  0
         ReflectedMappedProperty property =
 270  
             new ReflectedMappedProperty(clazz, parseResults.getPropertyName());
 271  
 
 272  0
         ReflectedMappedPropertyParseResults parseResultsMapped =
 273  
                 (ReflectedMappedPropertyParseResults) parseResults;
 274  
 
 275  0
         property.setAliases(parseResultsMapped.getAliases());                 
 276  0
         property.setType(parseResultsMapped.getPropertyType());
 277  0
         property.setKeyType(parseResultsMapped.getKeyType());
 278  0
         property.setContentType(parseResultsMapped.getContentType());
 279  0
         property.setReadMethod(parseResultsMapped.getReadMethod());
 280  0
         property.setWriteMethod(parseResultsMapped.getWriteMethod());
 281  0
         property.setGetMethod(parseResultsMapped.getGetMethod());
 282  0
         property.setPutMethod(parseResultsMapped.getPutMethod());
 283  0
         property.setRemoveMethod(parseResultsMapped.getRemoveMethod());
 284  0
         property.setKeySetMethod(parseResultsMapped.getKeySetMethod());
 285  0
         return property;
 286  
     }
 287  
 
 288  
     /**
 289  
      * Parser for the <code>getFooMap()</code> method:
 290  
      * <ul>
 291  
      *  <li>Return type not void</li>
 292  
      *  <li>Name starts with "get" followed by capitalized property name</li>
 293  
      *  <li>No parameters</li>
 294  
      * </ul>
 295  
      * 
 296  
      * We don't check if the parameter is a Map here. If it is not,
 297  
      * we want to recognize the method and them mark the corresponding
 298  
      * property as NotAProperty.
 299  
      */
 300  0
     public static class ReadAccessorMethodParser extends AccessorMethodParser {
 301  
         protected boolean testReturnType(Class returnType) {
 302  0
             return !returnType.equals(Void.TYPE);
 303  
         }
 304  
         protected String requiredPrefix() {
 305  0
             return "get";
 306  
         }
 307  
         protected int requiredParameterCount() {
 308  0
             return 0;
 309  
         }
 310  
         protected Class getValueType(Method method) {
 311  0
             return method.getReturnType();
 312  
         }
 313  
     }
 314  
     
 315  
     /**
 316  
      * Parser for the <code>setFooMap(Map)</code> method:
 317  
      * <ul>
 318  
      *  <li>Return type void</li>
 319  
      *  <li>Name starts with "set" followed by capitalized property name</li>
 320  
      *  <li>One parameter</li>
 321  
      * </ul>
 322  
      * 
 323  
      * We don't check if the parameter is a Map here. If it is not,
 324  
      * we want to recognize the method and them mark the corresponding
 325  
      * property as NotAProperty.
 326  
      */            
 327  0
     public static class WriteAccessorMethodParser extends AccessorMethodParser {
 328  
         protected boolean testReturnType(Class returnType) {
 329  0
             return returnType.equals(Void.TYPE);
 330  
         }
 331  
         protected int requiredParameterCount() {
 332  0
             return 1;
 333  
         }
 334  
         protected String requiredPrefix() {
 335  0
             return "set";
 336  
         }
 337  
         protected Class getValueType(Method method) {
 338  0
             return method.getParameterTypes()[0];
 339  
         }
 340  
     }
 341  
     
 342  
     /**
 343  
      * Parser for the <code>getFoo(key)</code> method:
 344  
      * <ul>
 345  
      *  <li>Return type not void</li>
 346  
      *  <li>Name starts with "get" followed by capitalized singular
 347  
      *      form of the property name</li>
 348  
      *  <li>One parameter</li>
 349  
      * </ul>
 350  
      */            
 351  0
     public static class GetAccessorMethodParser extends AccessorMethodParser {
 352  
         protected boolean testReturnType(Class returnType) {
 353  0
             return !returnType.equals(Void.TYPE);
 354  
         }
 355  
         protected String requiredPrefix() {
 356  0
             return "get";
 357  
         }
 358  
         protected int requiredParameterCount() {
 359  0
             return 1;
 360  
         }
 361  
         protected Class getValueType(Method method) {
 362  0
             return method.getReturnType();
 363  
         }
 364  
         protected Class getParameterType(Method method) {
 365  0
             return method.getParameterTypes()[0];
 366  
         }
 367  
     }
 368  
 
 369  
     /**
 370  
      * Parser for the <code>setFoo(key, value)</code> method:
 371  
      * <ul>
 372  
      *  <li>Return type void</li>
 373  
      *  <li>Name starts with "set" followed by capitalized singular
 374  
      *      form of the property name</li>
 375  
      *  <li>Two parameters</li>
 376  
      * </ul>
 377  
      */                        
 378  0
     public static class PutAccessorMethodParser extends AccessorMethodParser {
 379  
         protected String requiredPrefix() {
 380  0
             return "set";
 381  
         }
 382  
         protected int requiredParameterCount() {
 383  0
             return 2;
 384  
         }
 385  
         protected Class getValueType(Method method) {
 386  0
             return method.getParameterTypes()[1];
 387  
         }
 388  
         protected Class getParameterType(Method method) {
 389  0
             return method.getParameterTypes()[0];
 390  
         }
 391  
     }
 392  
     
 393  
     /**
 394  
      * Parser for the <code>removeFoo(key)</code> method:
 395  
      * <ul>
 396  
      *  <li>Name starts with "remove" followed by capitalized singular
 397  
      *      form of the property name</li>
 398  
      *  <li>One parameter</li>
 399  
      * </ul>
 400  
      */                        
 401  0
     public static class RemoveAccessorMethodParser
 402  
         extends AccessorMethodParser 
 403  
     {
 404  
         protected String requiredPrefix() {
 405  0
             return "remove";
 406  
         }
 407  
         protected int requiredParameterCount() {
 408  0
             return 1;
 409  
         }
 410  
         protected Class getValueType(Method method) {
 411  0
             Class returnType = method.getReturnType();
 412  0
             if (Void.TYPE.equals(returnType)) {
 413  0
                 return null;
 414  
             }
 415  0
             return returnType;
 416  
         }
 417  
         protected Class getParameterType(Method method) {
 418  0
             return method.getParameterTypes()[0];
 419  
         }
 420  
     }
 421  
     
 422  
     /**
 423  
      * Parser for the <code>getFooKeys()</code> method:
 424  
      * <ul>
 425  
      *  <li>Returns integer</li>
 426  
      *  <li>Name starts with "get" followed by capitalized singular
 427  
      *      form of the property name, followed by "Keys" or "KeySet"</li>
 428  
      *  <li>No parameters</li>
 429  
      * </ul>
 430  
      */                        
 431  0
     public static class KeySetAccessorMethodParser
 432  
         extends AccessorMethodParser 
 433  
     {
 434  
         protected boolean testReturnType(Class javaClass) {
 435  0
             return javaClass.isArray()
 436  0
                 || Collection.class.isAssignableFrom(javaClass);
 437  
         }
 438  
         protected String requiredPrefix() {
 439  0
             return "get";
 440  
         }
 441  
         protected int requiredParameterCount() {
 442  0
             return 0;
 443  
         }
 444  
         protected String testAndRemoveSuffix(String methodName) {
 445  0
             if (methodName.endsWith("Keys")) {
 446  0
                 return methodName.substring(0, methodName.length() - 4);
 447  
             }
 448  0
             if (methodName.endsWith("KeySet")) {
 449  0
                 return methodName.substring(0, methodName.length() - 6);
 450  
             }
 451  0
             return null;
 452  
         }
 453  
     }
 454  
 }