Coverage Report - org.simpleframework.xml.load.MethodPartFactory
 
Classes in this File Line Coverage Branch Coverage Complexity
MethodPartFactory
87%
34/39
100%
10/10
4.333
 
 1  
 /*
 2  
  * MethodPartFactory.java April 2007
 3  
  *
 4  
  * Copyright (C) 2007, Niall Gallagher <niallg@users.sf.net>
 5  
  *
 6  
  * This library is free software; you can redistribute it and/or
 7  
  * modify it under the terms of the GNU Lesser General Public
 8  
  * License as published by the Free Software Foundation.
 9  
  *
 10  
  * This library is distributed in the hope that it will be useful,
 11  
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 12  
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the 
 13  
  * GNU Lesser General Public License for more details.
 14  
  *
 15  
  * You should have received a copy of the GNU Lesser General 
 16  
  * Public License along with this library; if not, write to the 
 17  
  * Free Software Foundation, Inc., 59 Temple Place, Suite 330, 
 18  
  * Boston, MA  02111-1307  USA
 19  
  */
 20  
 
 21  
 package org.simpleframework.xml.load;
 22  
 
 23  
 import java.lang.annotation.Annotation;
 24  
 import java.lang.reflect.Method;
 25  
 import java.beans.Introspector;
 26  
 
 27  
 /**
 28  
  * The <code>MethodPartFactory</code> is used to create method parts
 29  
  * based on the method signature and the XML annotation. This is 
 30  
  * effectively where a method is classified as either a getter or a
 31  
  * setter method within an object. In order to determine the type of
 32  
  * method the method name is checked to see if it is prefixed with
 33  
  * either the "get", "is", or "set" tokens.
 34  
  * <p>
 35  
  * Once the method is determined to be a Java Bean method according 
 36  
  * to conventions the method signature is validated. If the method
 37  
  * signature does not follow a return type with no arguments for the
 38  
  * get method, and a single argument for the set method then this
 39  
  * will throw an exception.
 40  
  * 
 41  
  * @author Niall Gallagher
 42  
  * 
 43  
  * @see org.simpleframework.xml.load.MethodScanner
 44  
  */
 45  0
 final class MethodPartFactory {   
 46  
 
 47  
    /**
 48  
     * This is used to acquire a <code>MethodPart</code> for the name
 49  
     * and annotation of the provided method. This will determine the
 50  
     * method type by examining its signature. If the method follows
 51  
     * Java Bean conventions then either a setter method part or a
 52  
     * getter method part is returned. If the method does not comply
 53  
     * with the conventions an exception is thrown.
 54  
     * 
 55  
     * @param method this is the method to acquire the part for
 56  
     * @param label this is the annotation associated with the method
 57  
     * 
 58  
     * @return this is the method part object for the method
 59  
     * 
 60  
     * @throws Exception if Java Bean conventions are not followed
 61  
     */
 62  
    public static MethodPart getInstance(Method method, Annotation label) throws Exception {
 63  120
       MethodName name = getName(method, label);
 64  119
       MethodType type = name.getType();
 65  
       
 66  119
       if(type == MethodType.SET) {
 67  61
          return new SetPart(name, label);
 68  
       }
 69  58
       return new GetPart(name, label);
 70  
    }
 71  
    
 72  
    /**
 73  
     * This is used to acquire a <code>MethodName</code> for the name
 74  
     * and annotation of the provided method. This will determine the
 75  
     * method type by examining its signature. If the method follows
 76  
     * Java Bean conventions then either a setter method name or a
 77  
     * getter method name is returned. If the method does not comply
 78  
     * with the conventions an exception is thrown.
 79  
     * 
 80  
     * @param method this is the method to acquire the name for
 81  
     * @param label this is the annotation associated with the method
 82  
     * 
 83  
     * @return this is the method name object for the method
 84  
     * 
 85  
     * @throws Exception if Java Bean conventions are not followed
 86  
     */
 87  
    private static MethodName getName(Method method, Annotation label) throws Exception {
 88  120
       MethodType type = getPrefixType(method);
 89  
       
 90  120
       if(type == MethodType.GET) {
 91  58
          return getRead(method, type);
 92  
       }
 93  62
       if(type == MethodType.IS) {
 94  0
          return getRead(method, type);         
 95  
       }
 96  62
       if(type == MethodType.SET) {
 97  61
          return getWrite(method, type);
 98  
       }
 99  1
       throw new MethodException("Annotation %s must mark a set or get method", label);      
 100  
    }    
 101  
 
 102  
    /**
 103  
     * This is used to acquire a <code>MethodType</code> for the name
 104  
     * of the method provided. This will determine the method type by 
 105  
     * examining its prefix. If the name follows Java Bean conventions 
 106  
     * then either a setter method type is returned. If the name does
 107  
     * not comply with the naming conventions then null is returned.
 108  
     * 
 109  
     * @param method this is the method to acquire the type for
 110  
     * 
 111  
     * @return this is the method name object for the method    
 112  
     */
 113  
    private static MethodType getPrefixType(Method method) {
 114  120
       String name = method.getName();      
 115  
       
 116  120
       if(name.startsWith("get")) {
 117  58
          return MethodType.GET;
 118  
       }
 119  62
       if(name.startsWith("is")) {
 120  0
          return MethodType.IS;         
 121  
       }
 122  62
       if(name.startsWith("set")) {
 123  61
          return MethodType.SET;
 124  
       }
 125  1
       return null;
 126  
    }
 127  
    
 128  
    /**
 129  
     * This is used to acquire a <code>MethodName</code> for the name
 130  
     * and annotation of the provided method. This must be a getter
 131  
     * method, and so must have a return type that is not voide and 
 132  
     * have not arguments. If the method has arguments an exception 
 133  
     * is thrown, if not the Java Bean method name is provided.
 134  
     *
 135  
     * @param method this is the method to acquire the name for
 136  
     * @param type this is the method type to acquire the name for    
 137  
     * 
 138  
     * @return this is the method name object for the method
 139  
     * 
 140  
     * @throws Exception if Java Bean conventions are not followed
 141  
     */
 142  
    private static MethodName getRead(Method method, MethodType type) throws Exception {
 143  58
       Class[] list = method.getParameterTypes();
 144  58
       String real = method.getName();
 145  
          
 146  58
       if(list.length != 0) {
 147  0
          throw new MethodException("Get method %s in %s contains parameters", real, type);
 148  
       }
 149  58
       String name = getTypeName(real, type);
 150  
       
 151  58
       return new MethodName(method, type, name);
 152  
    }
 153  
 
 154  
    /**
 155  
     * This is used to acquire a <code>MethodName</code> for the name
 156  
     * and annotation of the provided method. This must be a setter
 157  
     * method, and so must accept a single argument, if it contains 
 158  
     * more or less than one argument an exception is thrown.
 159  
     * return type that is not voide and
 160  
     *
 161  
     * @param method this is the method to acquire the name for
 162  
     * @param type this is the method type to acquire the name for    
 163  
     * 
 164  
     * @return this is the method name object for the method
 165  
     * 
 166  
     * @throws Exception if Java Bean conventions are not followed
 167  
     */
 168  
    private static MethodName getWrite(Method method, MethodType type) throws Exception {
 169  61
       Class[] list = method.getParameterTypes();
 170  61
       String real = method.getName();
 171  
       
 172  61
       if(list.length != 1) {
 173  0
          throw new MethodException("Set method %s has invalid signature in %s", real, type);         
 174  
       }
 175  61
       String name = getTypeName(real, type);
 176  
       
 177  61
       return new MethodName(method, type, name);
 178  
    }
 179  
    
 180  
    /**
 181  
     * This is used to acquire the name of the method in a Java Bean
 182  
     * property style. Thus any "get", "is", or "set" prefix is 
 183  
     * removed from the name and the following character is changed
 184  
     * to lower case if it does not represent an acroynm.
 185  
     * 
 186  
     * @param name this is the name of the method to be converted
 187  
     * @param type this is the type of method the name represents
 188  
     * 
 189  
     * @return this returns the Java Bean name for the method
 190  
     */
 191  
    private static String getTypeName(String name, MethodType type) {
 192  119
       int prefix = type.getPrefix();
 193  119
       int size = name.length();
 194  
       
 195  119
       if(size > prefix) {
 196  119
          name = name.substring(prefix, size);
 197  
       }
 198  119
       return Introspector.decapitalize(name);          
 199  
    }
 200  
 }