Coverage Report - org.mule.util.generics.MethodParameter
 
Classes in this File Line Coverage Branch Coverage Complexity
MethodParameter
0%
0/76
0%
0/42
0
 
 1  
 /*
 2  
  * $Id: MethodParameter.java 19191 2010-08-25 21:05:23Z tcarlson $
 3  
  * --------------------------------------------------------------------------------------
 4  
  * Copyright (c) MuleSoft, Inc.  All rights reserved.  http://www.mulesoft.com
 5  
  *
 6  
  * The software in this package is published under the terms of the CPAL v1.0
 7  
  * license, a copy of which has been included with this distribution in the
 8  
  * LICENSE.txt file.
 9  
  */
 10  
 package org.mule.util.generics;
 11  
 
 12  
 import java.lang.annotation.Annotation;
 13  
 import java.lang.reflect.Constructor;
 14  
 import java.lang.reflect.Method;
 15  
 import java.lang.reflect.Type;
 16  
 import java.lang.reflect.TypeVariable;
 17  
 import java.util.HashMap;
 18  
 import java.util.Map;
 19  
 
 20  
 /**
 21  
  * Helper class that encapsulates the specification of a method parameter, i.e.
 22  
  * a Method or Constructor plus a parameter index and a nested type index for
 23  
  * a declared generic type. Useful as a specification object to pass along.
 24  
  * <p/>
 25  
  * author: Spring
 26  
  */
 27  
 public class MethodParameter
 28  
 {
 29  
 
 30  
     private Method method;
 31  
 
 32  
     private Constructor constructor;
 33  
 
 34  
     private final int parameterIndex;
 35  
 
 36  
     private Class<?> parameterType;
 37  
 
 38  
     private Type genericParameterType;
 39  
 
 40  
     private Annotation[] parameterAnnotations;
 41  
 
 42  
     private ParameterNameDiscoverer parameterNameDiscoverer;
 43  
 
 44  
     private String parameterName;
 45  
 
 46  0
     private int nestingLevel = 1;
 47  
 
 48  
     /**
 49  
      * Map from Integer level to Integer type index
 50  
      */
 51  
     private Map<Integer, Integer> typeIndexesPerLevel;
 52  
 
 53  
     Map<TypeVariable, Type> typeVariableMap;
 54  
 
 55  
 
 56  
     /**
 57  
      * Create a new MethodParameter for the given method, with nesting level 1.
 58  
      *
 59  
      * @param method         the Method to specify a parameter for
 60  
      * @param parameterIndex the index of the parameter
 61  
      */
 62  
     public MethodParameter(Method method, int parameterIndex)
 63  
     {
 64  0
         this(method, parameterIndex, 1);
 65  0
     }
 66  
 
 67  
     /**
 68  
      * Create a new MethodParameter for the given method.
 69  
      *
 70  
      * @param method         the Method to specify a parameter for
 71  
      * @param parameterIndex the index of the parameter
 72  
      *                       (-1 for the method return type; 0 for the first method parameter,
 73  
      *                       1 for the second method parameter, etc)
 74  
      * @param nestingLevel   the nesting level of the target type
 75  
      *                       (typically 1; e.g. in case of a List of Lists, 1 would indicate the
 76  
      *                       nested List, whereas 2 would indicate the element of the nested List)
 77  
      */
 78  
     public MethodParameter(Method method, int parameterIndex, int nestingLevel)
 79  0
     {
 80  0
         this.method = method;
 81  0
         this.parameterIndex = parameterIndex;
 82  0
         this.nestingLevel = nestingLevel;
 83  0
     }
 84  
 
 85  
     /**
 86  
      * Create a new MethodParameter for the given constructor, with nesting level 1.
 87  
      *
 88  
      * @param constructor    the Constructor to specify a parameter for
 89  
      * @param parameterIndex the index of the parameter
 90  
      */
 91  
     public MethodParameter(Constructor constructor, int parameterIndex)
 92  
     {
 93  0
         this(constructor, parameterIndex, 1);
 94  0
     }
 95  
 
 96  
     /**
 97  
      * Create a new MethodParameter for the given constructor.
 98  
      *
 99  
      * @param constructor    the Constructor to specify a parameter for
 100  
      * @param parameterIndex the index of the parameter
 101  
      * @param nestingLevel   the nesting level of the target type
 102  
      *                       (typically 1; e.g. in case of a List of Lists, 1 would indicate the
 103  
      *                       nested List, whereas 2 would indicate the element of the nested List)
 104  
      */
 105  
     public MethodParameter(Constructor constructor, int parameterIndex, int nestingLevel)
 106  0
     {
 107  0
         this.constructor = constructor;
 108  0
         this.parameterIndex = parameterIndex;
 109  0
         this.nestingLevel = nestingLevel;
 110  0
     }
 111  
 
 112  
     /**
 113  
      * Copy constructor, resulting in an independent MethodParameter object
 114  
      * based on the same metadata and cache state that the original object was in.
 115  
      *
 116  
      * @param original the original MethodParameter object to copy from
 117  
      */
 118  
     public MethodParameter(MethodParameter original)
 119  0
     {
 120  0
         this.method = original.method;
 121  0
         this.constructor = original.constructor;
 122  0
         this.parameterIndex = original.parameterIndex;
 123  0
         this.parameterType = original.parameterType;
 124  0
         this.parameterAnnotations = original.parameterAnnotations;
 125  0
         this.typeVariableMap = original.typeVariableMap;
 126  0
     }
 127  
 
 128  
 
 129  
     /**
 130  
      * Return the wrapped Method, if any.
 131  
      * <p>Note: Either Method or Constructor is available.
 132  
      *
 133  
      * @return the Method, or <code>null</code> if none
 134  
      */
 135  
     public Method getMethod()
 136  
     {
 137  0
         return this.method;
 138  
     }
 139  
 
 140  
     /**
 141  
      * Return the wrapped Constructor, if any.
 142  
      * <p>Note: Either Method or Constructor is available.
 143  
      *
 144  
      * @return the Constructor, or <code>null</code> if none
 145  
      */
 146  
     public Constructor getConstructor()
 147  
     {
 148  0
         return this.constructor;
 149  
     }
 150  
 
 151  
     /**
 152  
      * Return the class that declares the underlying Method or Constructor.
 153  
      */
 154  
     public Class getDeclaringClass()
 155  
     {
 156  0
         return (this.method != null ? this.method.getDeclaringClass() : this.constructor.getDeclaringClass());
 157  
     }
 158  
 
 159  
     /**
 160  
      * Return the index of the method/constructor parameter.
 161  
      *
 162  
      * @return the parameter index (never negative)
 163  
      */
 164  
     public int getParameterIndex()
 165  
     {
 166  0
         return this.parameterIndex;
 167  
     }
 168  
 
 169  
     /**
 170  
      * Set a resolved (generic) parameter type.
 171  
      */
 172  
     void setParameterType(Class<?> parameterType)
 173  
     {
 174  0
         this.parameterType = parameterType;
 175  0
     }
 176  
 
 177  
     /**
 178  
      * Return the type of the method/constructor parameter.
 179  
      *
 180  
      * @return the parameter type (never <code>null</code>)
 181  
      */
 182  
     public Class<?> getParameterType()
 183  
     {
 184  0
         if (this.parameterType == null)
 185  
         {
 186  0
             if (this.parameterIndex < 0)
 187  
             {
 188  0
                 this.parameterType = (this.method != null ? this.method.getReturnType() : null);
 189  
             }
 190  
             else
 191  
             {
 192  0
                 this.parameterType = (this.method != null ?
 193  
                         this.method.getParameterTypes()[this.parameterIndex] :
 194  
                         this.constructor.getParameterTypes()[this.parameterIndex]);
 195  
             }
 196  
         }
 197  0
         return this.parameterType;
 198  
     }
 199  
 
 200  
     /**
 201  
      * Return the generic type of the method/constructor parameter.
 202  
      *
 203  
      * @return the parameter type (never <code>null</code>)
 204  
      */
 205  
     public Type getGenericParameterType()
 206  
     {
 207  0
         if (this.genericParameterType == null)
 208  
         {
 209  0
             if (this.parameterIndex < 0)
 210  
             {
 211  0
                 this.genericParameterType = (this.method != null ? this.method.getGenericReturnType() : null);
 212  
             }
 213  
             else
 214  
             {
 215  0
                 this.genericParameterType = (this.method != null ?
 216  
                         this.method.getGenericParameterTypes()[this.parameterIndex] :
 217  
                         this.constructor.getGenericParameterTypes()[this.parameterIndex]);
 218  
             }
 219  
         }
 220  0
         return this.genericParameterType;
 221  
     }
 222  
 
 223  
     /**
 224  
      * Return the annotations associated with the target method/constructor itself.
 225  
      */
 226  
     public Annotation[] getMethodAnnotations()
 227  
     {
 228  0
         return (this.method != null ? this.method.getAnnotations() : this.constructor.getAnnotations());
 229  
     }
 230  
 
 231  
     /**
 232  
      * Return the method/constructor annotation of the given type, if available.
 233  
      *
 234  
      * @param annotationType the annotation type to look for
 235  
      * @return the annotation object, or <code>null</code> if not found
 236  
      */
 237  
     @SuppressWarnings("unchecked")
 238  
     public <T extends Annotation> T getMethodAnnotation(Class<T> annotationType)
 239  
     {
 240  0
         return (this.method != null ? this.method.getAnnotation(annotationType) :
 241  
                 (T) this.constructor.getAnnotation(annotationType));
 242  
     }
 243  
 
 244  
     /**
 245  
      * Return the annotations associated with the specific method/constructor parameter.
 246  
      */
 247  
     public Annotation[] getParameterAnnotations()
 248  
     {
 249  0
         if (this.parameterAnnotations == null)
 250  
         {
 251  0
             Annotation[][] annotationArray = (this.method != null ?
 252  
                     this.method.getParameterAnnotations() : this.constructor.getParameterAnnotations());
 253  0
             this.parameterAnnotations = annotationArray[this.parameterIndex];
 254  
         }
 255  0
         return this.parameterAnnotations;
 256  
     }
 257  
 
 258  
     /**
 259  
      * Return the parameter annotation of the given type, if available.
 260  
      *
 261  
      * @param annotationType the annotation type to look for
 262  
      * @return the annotation object, or <code>null</code> if not found
 263  
      */
 264  
     @SuppressWarnings("unchecked")
 265  
     public <T extends Annotation> T getParameterAnnotation(Class<T> annotationType)
 266  
     {
 267  0
         Annotation[] anns = getParameterAnnotations();
 268  0
         for (Annotation ann : anns)
 269  
         {
 270  0
             if (annotationType.isInstance(ann))
 271  
             {
 272  0
                 return (T) ann;
 273  
             }
 274  
         }
 275  0
         return null;
 276  
     }
 277  
 
 278  
     /**
 279  
      * Initialize parameter name discovery for this method parameter.
 280  
      * <p>This method does not actually try to retrieve the parameter name at
 281  
      * this point; it just allows discovery to happen when the application calls
 282  
      * {@link #getParameterName()} (if ever).
 283  
      */
 284  
     public void initParameterNameDiscovery(ParameterNameDiscoverer parameterNameDiscoverer)
 285  
     {
 286  0
         this.parameterNameDiscoverer = parameterNameDiscoverer;
 287  0
     }
 288  
 
 289  
     /**
 290  
      * Return the name of the method/constructor parameter.
 291  
      *
 292  
      * @return the parameter name (may be <code>null</code> if no
 293  
      *         parameter name metadata is contained in the class file or no
 294  
      *         {@link #initParameterNameDiscovery ParameterNameDiscoverer}
 295  
      *         has been set to begin with)
 296  
      */
 297  
     public String getParameterName()
 298  
     {
 299  0
         if (this.parameterNameDiscoverer != null)
 300  
         {
 301  0
             String[] parameterNames = (this.method != null ?
 302  
                     this.parameterNameDiscoverer.getParameterNames(this.method) :
 303  
                     this.parameterNameDiscoverer.getParameterNames(this.constructor));
 304  0
             if (parameterNames != null)
 305  
             {
 306  0
                 this.parameterName = parameterNames[this.parameterIndex];
 307  
             }
 308  0
             this.parameterNameDiscoverer = null;
 309  
         }
 310  0
         return this.parameterName;
 311  
     }
 312  
 
 313  
     /**
 314  
      * Increase this parameter's nesting level.
 315  
      *
 316  
      * @see #getNestingLevel()
 317  
      */
 318  
     public void increaseNestingLevel()
 319  
     {
 320  0
         this.nestingLevel++;
 321  0
     }
 322  
 
 323  
     /**
 324  
      * Decrease this parameter's nesting level.
 325  
      *
 326  
      * @see #getNestingLevel()
 327  
      */
 328  
     public void decreaseNestingLevel()
 329  
     {
 330  0
         getTypeIndexesPerLevel().remove(this.nestingLevel);
 331  0
         this.nestingLevel--;
 332  0
     }
 333  
 
 334  
     /**
 335  
      * Return the nesting level of the target type
 336  
      * (typically 1; e.g. in case of a List of Lists, 1 would indicate the
 337  
      * nested List, whereas 2 would indicate the element of the nested List).
 338  
      */
 339  
     public int getNestingLevel()
 340  
     {
 341  0
         return this.nestingLevel;
 342  
     }
 343  
 
 344  
     /**
 345  
      * Set the type index for the current nesting level.
 346  
      *
 347  
      * @param typeIndex the corresponding type index
 348  
      *                  (or <code>null</code> for the default type index)
 349  
      * @see #getNestingLevel()
 350  
      */
 351  
     public void setTypeIndexForCurrentLevel(int typeIndex)
 352  
     {
 353  0
         getTypeIndexesPerLevel().put(this.nestingLevel, typeIndex);
 354  0
     }
 355  
 
 356  
     /**
 357  
      * Return the type index for the current nesting level.
 358  
      *
 359  
      * @return the corresponding type index, or <code>null</code>
 360  
      *         if none specified (indicating the default type index)
 361  
      * @see #getNestingLevel()
 362  
      */
 363  
     public Integer getTypeIndexForCurrentLevel()
 364  
     {
 365  0
         return getTypeIndexForLevel(this.nestingLevel);
 366  
     }
 367  
 
 368  
     /**
 369  
      * Return the type index for the specified nesting level.
 370  
      *
 371  
      * @param nestingLevel the nesting level to check
 372  
      * @return the corresponding type index, or <code>null</code>
 373  
      *         if none specified (indicating the default type index)
 374  
      */
 375  
     public Integer getTypeIndexForLevel(int nestingLevel)
 376  
     {
 377  0
         return getTypeIndexesPerLevel().get(nestingLevel);
 378  
     }
 379  
 
 380  
     /**
 381  
      * Obtain the (lazily constructed) type-indexes-per-level Map.
 382  
      */
 383  
     private Map<Integer, Integer> getTypeIndexesPerLevel()
 384  
     {
 385  0
         if (this.typeIndexesPerLevel == null)
 386  
         {
 387  0
             this.typeIndexesPerLevel = new HashMap<Integer, Integer>(4);
 388  
         }
 389  0
         return this.typeIndexesPerLevel;
 390  
     }
 391  
 
 392  
 
 393  
     /**
 394  
      * Create a new MethodParameter for the given method or constructor.
 395  
      * <p>This is a convenience constructor for scenarios where a
 396  
      * Method or Constructor reference is treated in a generic fashion.
 397  
      *
 398  
      * @param methodOrConstructor the Method or Constructor to specify a parameter for
 399  
      * @param parameterIndex      the index of the parameter
 400  
      * @return the corresponding MethodParameter instance
 401  
      */
 402  
     public static MethodParameter forMethodOrConstructor(Object methodOrConstructor, int parameterIndex)
 403  
     {
 404  0
         if (methodOrConstructor instanceof Method)
 405  
         {
 406  0
             return new MethodParameter((Method) methodOrConstructor, parameterIndex);
 407  
         }
 408  0
         else if (methodOrConstructor instanceof Constructor) {
 409  0
             return new MethodParameter((Constructor) methodOrConstructor, parameterIndex);
 410  
         }
 411  
         else {
 412  0
             throw new IllegalArgumentException(
 413  
                     "Given object [" + methodOrConstructor + "] is neither a Method nor a Constructor");
 414  
         }
 415  
     }
 416  
 
 417  
 }