View Javadoc
1   /*
2    * Copyright (c) 2006 JMockit developers
3    * This file is subject to the terms of the MIT license (see LICENSE.txt).
4    */
5   package mockit.internal.reflection;
6   
7   import static mockit.internal.reflection.MethodReflection.JAVA_LANG;
8   import static mockit.internal.util.Utilities.JAVA8;
9   
10  import edu.umd.cs.findbugs.annotations.NonNull;
11  
12  import java.lang.reflect.Method;
13  
14  import mockit.Invocation;
15  import mockit.internal.util.AutoBoxing;
16  import mockit.internal.util.GeneratedClasses;
17  
18  import org.checkerframework.checker.index.qual.NonNegative;
19  
20  public final class ParameterReflection {
21      @NonNull
22      public static final Class<?>[] NO_PARAMETERS = {};
23  
24      private ParameterReflection() {
25      }
26  
27      @NonNull
28      static String getParameterTypesDescription(@NonNull Class<?>[] paramTypes) {
29          StringBuilder paramTypesDesc = new StringBuilder(200);
30          paramTypesDesc.append('(');
31  
32          String sep = "";
33  
34          for (Class<?> paramType : paramTypes) {
35              String typeName = JAVA_LANG.matcher(paramType.getCanonicalName()).replaceAll("");
36              paramTypesDesc.append(sep).append(typeName);
37              sep = ", ";
38          }
39  
40          paramTypesDesc.append(')');
41          return paramTypesDesc.toString();
42      }
43  
44      @NonNull
45      public static Class<?>[] getArgumentTypesFromArgumentValues(@NonNull Object... args) {
46          if (args.length == 0) {
47              return NO_PARAMETERS;
48          }
49  
50          Class<?>[] argTypes = new Class<?>[args.length];
51  
52          for (int i = 0; i < args.length; i++) {
53              argTypes[i] = getArgumentTypeFromArgumentValue(i, args);
54          }
55  
56          return argTypes;
57      }
58  
59      @NonNull
60      private static Class<?> getArgumentTypeFromArgumentValue(int i, @NonNull Object[] args) {
61          Object arg = args[i];
62  
63          if (arg == null) {
64              throw new IllegalArgumentException("Invalid null value passed as argument " + i);
65          }
66  
67          Class<?> argType;
68  
69          if (arg instanceof Class<?>) {
70              argType = (Class<?>) arg;
71              args[i] = null;
72          } else {
73              argType = GeneratedClasses.getMockedClass(arg);
74          }
75  
76          return argType;
77      }
78  
79      @NonNull
80      public static Object[] argumentsWithExtraFirstValue(@NonNull Object[] args, @NonNull Object firstValue) {
81          Object[] args2 = new Object[1 + args.length];
82          args2[0] = firstValue;
83          System.arraycopy(args, 0, args2, 1, args.length);
84          return args2;
85      }
86  
87      static boolean hasMoreSpecificTypes(@NonNull Class<?>[] currentTypes, @NonNull Class<?>[] previousTypes) {
88          for (int i = 0; i < currentTypes.length; i++) {
89              Class<?> current = wrappedIfPrimitive(currentTypes[i]);
90              Class<?> previous = wrappedIfPrimitive(previousTypes[i]);
91  
92              if (current != previous && previous.isAssignableFrom(current)) {
93                  return true;
94              }
95          }
96  
97          return false;
98      }
99  
100     @NonNull
101     private static Class<?> wrappedIfPrimitive(@NonNull Class<?> parameterType) {
102         if (parameterType.isPrimitive()) {
103             Class<?> wrapperType = AutoBoxing.getWrapperType(parameterType);
104             assert wrapperType != null;
105             return wrapperType;
106         }
107 
108         return parameterType;
109     }
110 
111     static boolean acceptsArgumentTypes(@NonNull Class<?>[] paramTypes, @NonNull Class<?>[] argTypes,
112             int firstParameter) {
113         for (int i = firstParameter; i < paramTypes.length; i++) {
114             Class<?> parType = paramTypes[i];
115             Class<?> argType = argTypes[i - firstParameter];
116 
117             if (!isSameTypeIgnoringAutoBoxing(parType, argType) && !parType.isAssignableFrom(argType)) {
118                 return false;
119             }
120         }
121 
122         return true;
123     }
124 
125     static boolean isSameTypeIgnoringAutoBoxing(@NonNull Class<?> firstType, @NonNull Class<?> secondType) {
126         return firstType == secondType || firstType.isPrimitive() && isWrapperOfPrimitiveType(firstType, secondType)
127                 || secondType.isPrimitive() && isWrapperOfPrimitiveType(secondType, firstType);
128     }
129 
130     private static boolean isWrapperOfPrimitiveType(@NonNull Class<?> primitiveType, @NonNull Class<?> otherType) {
131         return primitiveType == AutoBoxing.getPrimitiveType(otherType);
132     }
133 
134     static int indexOfFirstRealParameter(@NonNull Class<?>[] mockParameterTypes,
135             @NonNull Class<?>[] realParameterTypes) {
136         int extraParameters = mockParameterTypes.length - realParameterTypes.length;
137 
138         if (extraParameters == 1) {
139             return mockParameterTypes[0] == Invocation.class ? 1 : -1;
140         }
141 
142         if (extraParameters != 0) {
143             return -1;
144         }
145 
146         return 0;
147     }
148 
149     static boolean matchesParameterTypes(@NonNull Class<?>[] declaredTypes, @NonNull Class<?>[] specifiedTypes,
150             int firstParameter) {
151         for (int i = firstParameter; i < declaredTypes.length; i++) {
152             Class<?> declaredType = declaredTypes[i];
153             Class<?> specifiedType = specifiedTypes[i - firstParameter];
154 
155             if (!isSameTypeIgnoringAutoBoxing(declaredType, specifiedType)) {
156                 return false;
157             }
158         }
159 
160         return true;
161     }
162 
163     @NonNegative
164     public static int getParameterCount(@NonNull Method method) {
165         // noinspection Since15
166         return JAVA8 ? method.getParameterCount() : method.getParameterTypes().length;
167     }
168 }