Coverage Report - org.apache.commons.clazz.reflect.common.AccessorMethodParser
 
Classes in this File Line Coverage Branch Coverage Complexity
AccessorMethodParser
0%
0/56
0%
0/34
3.636
 
 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.lang.reflect.Modifier;
 20  
 
 21  
 /**
 22  
  * 
 23  
  * @author <a href="mailto:dmitri@apache.org">Dmitri Plotnikov</a>
 24  
  * @version $Id: AccessorMethodParser.java 155436 2005-02-26 13:17:48Z dirkv $
 25  
  */
 26  0
 public class AccessorMethodParser {
 27  
     
 28  
     /**
 29  
      * If a method parsed by this parser must have a number or parameters,
 30  
      * override and return that number.  
 31  
      */
 32  
     protected int requiredParameterCount() {
 33  0
         return -1;
 34  
     }
 35  
 
 36  
     /**
 37  
      * If a method parsed by this parser must have a certain prefix,
 38  
      * override and return a non-null prefix string  
 39  
      */
 40  
     protected String requiredPrefix() {
 41  0
         return null;
 42  
     }
 43  
 
 44  
     /**
 45  
      * To check constraints on the return type of methods parsed
 46  
      * by this parser, override and perform the check.
 47  
      *  
 48  
      * @param javaClass The return type of the method (never null)
 49  
      * @return boolean True if the return type passes the parser's constraints
 50  
      */    
 51  
     protected boolean testReturnType(Class javaClass) {
 52  0
         return true;
 53  
     }
 54  
     
 55  
     /**
 56  
      * To check constraints on the type of a parameter, override 
 57  
      * and perform the check.
 58  
      *  
 59  
      * @param javaClass The return type of the method (never null)
 60  
      * @return boolean True if the return type passes the parser's constraints
 61  
      */    
 62  
     protected boolean testParameterType(int index, Class parameterType) {
 63  0
         return true;
 64  
     }
 65  
     
 66  
     /**
 67  
      * If a method parsed by this parser must have a certain suffix,
 68  
      * override this method, check that it does and remove the
 69  
      * suffix.
 70  
      */
 71  
     protected String testAndRemoveSuffix(String methodName) {
 72  0
         return methodName;
 73  
     }
 74  
     
 75  
     /**
 76  
      * Returns true if the character can be the first character of a Capitalized
 77  
      * property name.
 78  
      */
 79  
     protected boolean testFirstCharacterOfPropertyName(char ch) {
 80  0
         return Character.isUpperCase(ch);
 81  
     }
 82  
     
 83  
     /**
 84  
      * Extract the value type from the method. Depending on the type
 85  
      * of method, it could be the return type or the type of a parameter.
 86  
      */
 87  
     protected Class getValueType(Method method) {
 88  0
         return null;
 89  
     }
 90  
     
 91  
     /**
 92  
      * Extract the parameter type from the method, if it has one. 
 93  
      * For example a mapped property "get" method might have
 94  
      * a "key" parameter.
 95  
      */
 96  
     protected Class getParameterType(Method method) {
 97  0
         return null;
 98  
     }
 99  
 
 100  
     /**
 101  
      * Parses the supplied method according to the parser's configuration.
 102  
      * If the parse process fails, returns null.
 103  
      * 
 104  
      * @param method
 105  
      * @return AccessorMethodParseResults
 106  
      */
 107  
     public AccessorMethodParseResults parse(Method method) {
 108  0
         int modifiers = method.getModifiers();
 109  
 
 110  
         // An accessor methods must be public and non-static
 111  0
         if (!Modifier.isPublic(modifiers) || Modifier.isStatic(modifiers)) {
 112  0
             return null;
 113  
         }
 114  
 
 115  0
         Class returnType = method.getReturnType();
 116  0
         if (returnType == null) {
 117  0
             returnType = Void.TYPE; 
 118  
         }
 119  0
         if (!testReturnType(returnType)) {
 120  0
             return null;
 121  
         }
 122  
         
 123  0
         int reqParamCount = requiredParameterCount();
 124  0
         if (reqParamCount != -1) {
 125  0
             Class paramTypes[] = method.getParameterTypes();
 126  0
             if (paramTypes.length != reqParamCount) {
 127  0
                 return null;
 128  
             }
 129  
             
 130  0
             for (int i = 0; i < paramTypes.length; i++) {
 131  0
                 if (!testParameterType(i, paramTypes[i])) {
 132  0
                     return null;
 133  
                 }
 134  
             }
 135  
         }
 136  
         
 137  0
         String propertyName = getPropertyName(method);
 138  0
         if (propertyName == null) {
 139  0
             return null;
 140  
         }
 141  
         
 142  0
         return new AccessorMethodParseResults(
 143  
                         method, 
 144  
                         propertyName, 
 145  
                         getValueType(method), 
 146  
                         getParameterType(method));
 147  
     }
 148  
     
 149  
     /**
 150  
      * Parse method name and return the corresponding property name.
 151  
      * Return null if the method name does not satisfy the parser's
 152  
      * grammar.
 153  
      * <p>
 154  
      * The default implementation of the method checks if the 
 155  
      * method name starts with the specified prefix followed
 156  
      * by an optionally capitalized property name.
 157  
      * 
 158  
      * @param methodName
 159  
      * @return String
 160  
      */
 161  
     protected String getPropertyName(Method method) {
 162  0
         String name = method.getName();
 163  0
         name = testAndRemoveSuffix(name);
 164  0
         if (name == null) {
 165  0
             return null;
 166  
         }
 167  
         
 168  0
         String prefix = requiredPrefix(); 
 169  0
         if (prefix == null) {
 170  0
             return name;
 171  
         }
 172  
         
 173  0
         int prefixLength = prefix.length();
 174  
         
 175  0
         if (name.length() <= prefixLength) {
 176  0
             return null;
 177  
         }
 178  
         
 179  0
         if (!name.startsWith(prefix)) {
 180  0
             return null;
 181  
         }
 182  
         
 183  0
         if (!testFirstCharacterOfPropertyName(name.charAt(prefixLength))) {
 184  0
             return null;
 185  
         }
 186  
         
 187  0
         return decapitalize(name.substring(prefixLength));
 188  
     }
 189  
     
 190  
     /**
 191  
      * Changes the first character of the <code>string</code>
 192  
      * to lower case, unless the second character is
 193  
      * upper case.  This is consistent with the JavaBean specification.
 194  
      * 
 195  
      * @param candidate
 196  
      * @return String
 197  
      */
 198  
     protected String decapitalize(String string) {
 199  0
         char firstChar = string.charAt(0);
 200  0
         if (!Character.isUpperCase(firstChar)) {
 201  0
             return string;
 202  
         }
 203  
         
 204  0
         int len = string.length();
 205  0
         if (len == 1) {
 206  0
             return String.valueOf(Character.toLowerCase(firstChar));
 207  
         }
 208  0
         else if (Character.isLowerCase(string.charAt(1))) {
 209  0
             char buffer[] = new char[len];
 210  0
             buffer[0] = Character.toLowerCase(firstChar);
 211  0
             string.getChars(1, len, buffer, 1);
 212  0
             return new String(buffer);
 213  
         }
 214  
         
 215  0
         return string;
 216  
     }
 217  
 }