1
2
3
4
5 package mockit.internal.util;
6
7 import static java.util.Collections.emptyIterator;
8 import static java.util.Collections.emptyList;
9 import static java.util.Collections.emptyMap;
10 import static java.util.Collections.emptySet;
11 import static java.util.Collections.enumeration;
12 import static java.util.Collections.unmodifiableSortedMap;
13 import static java.util.Collections.unmodifiableSortedSet;
14
15 import static mockit.internal.util.Utilities.JAVA8;
16
17 import edu.umd.cs.findbugs.annotations.NonNull;
18 import edu.umd.cs.findbugs.annotations.Nullable;
19
20 import java.lang.reflect.Array;
21 import java.lang.reflect.Type;
22 import java.util.HashMap;
23 import java.util.Map;
24 import java.util.NoSuchElementException;
25 import java.util.Optional;
26 import java.util.OptionalDouble;
27 import java.util.OptionalInt;
28 import java.util.OptionalLong;
29 import java.util.PrimitiveIterator;
30 import java.util.Spliterators;
31 import java.util.TreeMap;
32 import java.util.TreeSet;
33 import java.util.function.DoubleConsumer;
34 import java.util.function.IntConsumer;
35 import java.util.function.LongConsumer;
36 import java.util.stream.DoubleStream;
37 import java.util.stream.IntStream;
38 import java.util.stream.LongStream;
39 import java.util.stream.Stream;
40
41 import mockit.asm.types.ArrayType;
42
43
44
45
46 @SuppressWarnings("ZeroLengthArrayAllocation")
47 public final class DefaultValues {
48 private DefaultValues() {
49 }
50
51 private static final Integer ZERO_INT = 0;
52 private static final Long ZERO_LONG = 0L;
53 private static final Float ZERO_FLOAT = 0.0F;
54 private static final Double ZERO_DOUBLE = 0.0;
55 private static final Byte ZERO_BYTE = 0;
56 private static final Short ZERO_SHORT = 0;
57 private static final Character ZERO_CHAR = '\0';
58
59 private static final Map<String, Object> TYPE_DESC_TO_VALUE_MAP = new HashMap<>();
60 private static final Map<String, Object> ELEM_TYPE_TO_ONE_D_ARRAY = new HashMap<>();
61 static {
62 TYPE_DESC_TO_VALUE_MAP.put("Z", Boolean.FALSE);
63 TYPE_DESC_TO_VALUE_MAP.put("C", ZERO_CHAR);
64 TYPE_DESC_TO_VALUE_MAP.put("B", ZERO_BYTE);
65 TYPE_DESC_TO_VALUE_MAP.put("S", ZERO_SHORT);
66 TYPE_DESC_TO_VALUE_MAP.put("I", ZERO_INT);
67 TYPE_DESC_TO_VALUE_MAP.put("F", ZERO_FLOAT);
68 TYPE_DESC_TO_VALUE_MAP.put("J", ZERO_LONG);
69 TYPE_DESC_TO_VALUE_MAP.put("D", ZERO_DOUBLE);
70 TYPE_DESC_TO_VALUE_MAP.put("Ljava/lang/Boolean;", Boolean.FALSE);
71 TYPE_DESC_TO_VALUE_MAP.put("Ljava/lang/Character;", ZERO_CHAR);
72 TYPE_DESC_TO_VALUE_MAP.put("Ljava/lang/Byte;", ZERO_BYTE);
73 TYPE_DESC_TO_VALUE_MAP.put("Ljava/lang/Short;", ZERO_SHORT);
74 TYPE_DESC_TO_VALUE_MAP.put("Ljava/lang/Integer;", ZERO_INT);
75 TYPE_DESC_TO_VALUE_MAP.put("Ljava/lang/Float;", ZERO_FLOAT);
76 TYPE_DESC_TO_VALUE_MAP.put("Ljava/lang/Long;", ZERO_LONG);
77 TYPE_DESC_TO_VALUE_MAP.put("Ljava/lang/Double;", ZERO_DOUBLE);
78 TYPE_DESC_TO_VALUE_MAP.put("Ljava/lang/Iterable;", emptyList());
79 TYPE_DESC_TO_VALUE_MAP.put("Ljava/util/Enumeration;", enumeration(emptyList()));
80 TYPE_DESC_TO_VALUE_MAP.put("Ljava/util/Collection;", emptyList());
81 TYPE_DESC_TO_VALUE_MAP.put("Ljava/util/List;", emptyList());
82 TYPE_DESC_TO_VALUE_MAP.put("Ljava/util/Set;", emptySet());
83 TYPE_DESC_TO_VALUE_MAP.put("Ljava/util/SortedSet;", unmodifiableSortedSet(new TreeSet<>()));
84 TYPE_DESC_TO_VALUE_MAP.put("Ljava/util/Map;", emptyMap());
85 TYPE_DESC_TO_VALUE_MAP.put("Ljava/util/SortedMap;", unmodifiableSortedMap(new TreeMap<>()));
86 TYPE_DESC_TO_VALUE_MAP.put("Ljava/util/Iterator;", emptyIterator());
87 TYPE_DESC_TO_VALUE_MAP.put("Ljava/util/ListIterator;", emptyList().listIterator());
88
89 ELEM_TYPE_TO_ONE_D_ARRAY.put("[Z", new boolean[0]);
90 ELEM_TYPE_TO_ONE_D_ARRAY.put("[C", new char[0]);
91 ELEM_TYPE_TO_ONE_D_ARRAY.put("[B", new byte[0]);
92 ELEM_TYPE_TO_ONE_D_ARRAY.put("[S", new short[0]);
93 ELEM_TYPE_TO_ONE_D_ARRAY.put("[I", new int[0]);
94 ELEM_TYPE_TO_ONE_D_ARRAY.put("[F", new float[0]);
95 ELEM_TYPE_TO_ONE_D_ARRAY.put("[J", new long[0]);
96 ELEM_TYPE_TO_ONE_D_ARRAY.put("[D", new double[0]);
97 ELEM_TYPE_TO_ONE_D_ARRAY.put("[Ljava/lang/Object;", new Object[0]);
98 ELEM_TYPE_TO_ONE_D_ARRAY.put("[Ljava/lang/String;", new String[0]);
99
100 if (JAVA8) {
101 addJava8TypeMapEntries();
102 }
103 }
104
105 private static void addJava8TypeMapEntries() {
106 TYPE_DESC_TO_VALUE_MAP.put("Ljava/util/Optional;", Optional.empty());
107 TYPE_DESC_TO_VALUE_MAP.put("Ljava/util/OptionalInt;", OptionalInt.empty());
108 TYPE_DESC_TO_VALUE_MAP.put("Ljava/util/OptionalLong;", OptionalLong.empty());
109 TYPE_DESC_TO_VALUE_MAP.put("Ljava/util/OptionalDouble;", OptionalDouble.empty());
110 TYPE_DESC_TO_VALUE_MAP.put("Ljava/util/Spliterator;", Spliterators.emptySpliterator());
111 TYPE_DESC_TO_VALUE_MAP.put("Ljava/util/Spliterator$OfInt;", Spliterators.emptyIntSpliterator());
112 TYPE_DESC_TO_VALUE_MAP.put("Ljava/util/Spliterator$OfLong;", Spliterators.emptyLongSpliterator());
113 TYPE_DESC_TO_VALUE_MAP.put("Ljava/util/Spliterator$OfDouble;", Spliterators.emptyDoubleSpliterator());
114
115 TYPE_DESC_TO_VALUE_MAP.put("Ljava/util/PrimitiveIterator$OfInt;", new PrimitiveIterator.OfInt() {
116 @Override
117 public int nextInt() {
118 throw new NoSuchElementException();
119 }
120
121 @Override
122 public Integer next() {
123 throw new NoSuchElementException();
124 }
125
126 @Override
127 public boolean hasNext() {
128 return false;
129 }
130
131 @Override
132 public void forEachRemaining(IntConsumer action) {
133 }
134 });
135 TYPE_DESC_TO_VALUE_MAP.put("Ljava/util/PrimitiveIterator$OfLong;", new PrimitiveIterator.OfLong() {
136 @Override
137 public long nextLong() {
138 throw new NoSuchElementException();
139 }
140
141 @Override
142 public Long next() {
143 throw new NoSuchElementException();
144 }
145
146 @Override
147 public boolean hasNext() {
148 return false;
149 }
150
151 @Override
152 public void forEachRemaining(LongConsumer action) {
153 }
154 });
155 TYPE_DESC_TO_VALUE_MAP.put("Ljava/util/PrimitiveIterator$OfDouble;", new PrimitiveIterator.OfDouble() {
156 @Override
157 public double nextDouble() {
158 throw new NoSuchElementException();
159 }
160
161 @Override
162 public Double next() {
163 throw new NoSuchElementException();
164 }
165
166 @Override
167 public boolean hasNext() {
168 return false;
169 }
170
171 @Override
172 public void forEachRemaining(DoubleConsumer action) {
173 }
174 });
175
176
177
178 try {
179 TYPE_DESC_TO_VALUE_MAP.put("Ljava/util/stream/Stream;", Stream.class.getMethod("empty").invoke(null));
180 TYPE_DESC_TO_VALUE_MAP.put("Ljava/util/stream/IntStream;", IntStream.class.getMethod("empty").invoke(null));
181 TYPE_DESC_TO_VALUE_MAP.put("Ljava/util/stream/LongStream;",
182 LongStream.class.getMethod("empty").invoke(null));
183 TYPE_DESC_TO_VALUE_MAP.put("Ljava/util/stream/DoubleStream;",
184 DoubleStream.class.getMethod("empty").invoke(null));
185 } catch (Exception ignore) {
186 }
187 }
188
189 @NonNull
190 public static String getReturnTypeDesc(@NonNull String methodNameAndDesc) {
191 int rightParen = methodNameAndDesc.indexOf(')') + 1;
192 return methodNameAndDesc.substring(rightParen);
193 }
194
195 @Nullable
196 public static Object computeForType(@NonNull String typeDesc) {
197 char typeDescChar = typeDesc.charAt(0);
198
199 if (typeDescChar == 'V') {
200 return null;
201 }
202
203 Object defaultValue = TYPE_DESC_TO_VALUE_MAP.get(typeDesc);
204
205 if (defaultValue != null) {
206 return defaultValue;
207 }
208
209 if (typeDescChar == 'L') {
210 return null;
211 }
212
213
214 return computeForArrayType(typeDesc);
215 }
216
217 @NonNull
218 public static Object computeForArrayType(@NonNull String typeDesc) {
219 Object emptyArray = ELEM_TYPE_TO_ONE_D_ARRAY.get(typeDesc);
220
221 if (emptyArray == null) {
222 emptyArray = newEmptyArray(typeDesc);
223 }
224
225 return emptyArray;
226 }
227
228 @NonNull
229 private static Object newEmptyArray(@NonNull String typeDesc) {
230 ArrayType type = ArrayType.create(typeDesc);
231 Class<?> elementType = TypeDescriptor.getClassForType(type.getElementType());
232
233 return Array.newInstance(elementType, new int[type.getDimensions()]);
234 }
235
236 @Nullable
237 public static Object computeForType(@NonNull Class<?> type) {
238 if (type.isArray()) {
239 return Array.newInstance(type.getComponentType(), 0);
240 }
241
242 if (type != void.class && type.isPrimitive()) {
243 return defaultValueForPrimitiveType(type);
244 }
245
246 return computeForWrapperType(type);
247 }
248
249 @NonNull
250 public static Object defaultValueForPrimitiveType(@NonNull Class<?> type) {
251 if (type == int.class) {
252 return ZERO_INT;
253 }
254 if (type == boolean.class) {
255 return Boolean.FALSE;
256 }
257 if (type == long.class) {
258 return ZERO_LONG;
259 }
260 if (type == double.class) {
261 return ZERO_DOUBLE;
262 }
263 if (type == float.class) {
264 return ZERO_FLOAT;
265 }
266 if (type == char.class) {
267 return ZERO_CHAR;
268 }
269 if (type == byte.class) {
270 return ZERO_BYTE;
271 }
272 return ZERO_SHORT;
273 }
274
275 @Nullable
276 @SuppressWarnings("unchecked")
277 public static <T> T computeForWrapperType(@NonNull Type type) {
278 if (type == Integer.class) {
279 return (T) ZERO_INT;
280 }
281
282 if (type == Boolean.class) {
283 return (T) Boolean.FALSE;
284 }
285
286 if (type == Long.class) {
287 return (T) ZERO_LONG;
288 }
289
290 if (type == Double.class) {
291 return (T) ZERO_DOUBLE;
292 }
293
294 if (type == Float.class) {
295 return (T) ZERO_FLOAT;
296 }
297
298 if (type == Character.class) {
299 return (T) ZERO_CHAR;
300 }
301
302 if (type == Byte.class) {
303 return (T) ZERO_BYTE;
304 }
305
306 if (type == Short.class) {
307 return (T) ZERO_SHORT;
308 }
309
310 return null;
311 }
312
313 @Nullable
314 public static Object computeForReturnType(@NonNull String methodNameAndDesc) {
315 String typeDesc = getReturnTypeDesc(methodNameAndDesc);
316 return computeForType(typeDesc);
317 }
318 }