1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19 package io.earcam.instrumental.reflect;
20
21 import static java.util.Arrays.asList;
22 import static java.util.Collections.unmodifiableMap;
23 import static java.util.Collections.unmodifiableSet;
24 import static java.util.stream.Collectors.toMap;
25 import static java.util.stream.Collectors.toSet;
26
27 import java.lang.reflect.Type;
28 import java.util.Arrays;
29 import java.util.Collection;
30 import java.util.HashMap;
31 import java.util.List;
32 import java.util.Map;
33 import java.util.Objects;
34 import java.util.Set;
35 import java.util.function.Predicate;
36 import java.util.stream.Collectors;
37 import java.util.stream.Stream;
38
39 import io.earcam.unexceptional.Exceptional;
40
41
42
43
44
45
46
47 public final class Types {
48
49 private static final ClassLoader CLASS_LOADER = Types.class.getClassLoader();
50
51
52
53
54 private static final Set<String> PRIMITIVES = namesOf(
55 short.class, int.class, long.class, float.class, double.class, char.class, byte.class, boolean.class, void.class);
56
57 private static final Set<String> WRAPPERS = namesOf(
58 Short.class, Integer.class, Long.class, Float.class, Double.class, Character.class, Byte.class, Boolean.class, Void.class);
59
60 private static final Map<Class<?>, Class<?>> WRAPPER_TO_PRIMITIVE;
61 private static final Map<Class<?>, Class<?>> PRIMITIVE_TO_WRAPPER;
62 static {
63 Map<Class<?>, Class<?>> map = new HashMap<>(8);
64 map.put(Boolean.class, boolean.class);
65 map.put(Byte.class, byte.class);
66 map.put(Character.class, char.class);
67 map.put(Double.class, double.class);
68 map.put(Float.class, float.class);
69 map.put(Integer.class, int.class);
70 map.put(Long.class, long.class);
71 map.put(Short.class, short.class);
72 map.put(Void.class, void.class);
73 WRAPPER_TO_PRIMITIVE = unmodifiableMap(map);
74 PRIMITIVE_TO_WRAPPER = unmodifiableMap(WRAPPER_TO_PRIMITIVE.entrySet().stream().collect(toMap(Map.Entry::getValue, Map.Entry::getKey)));
75 }
76
77
78 private Types()
79 {}
80
81
82 private static Set<String> namesOf(Class<?>... items)
83 {
84 return unmodifiableSet(asList(items).stream()
85 .map(Class::getCanonicalName)
86 .collect(toSet()));
87 }
88
89
90
91
92
93
94
95
96
97
98 public static Class<?> wrapperToPrimitive(Class<?> type)
99 {
100 return WRAPPER_TO_PRIMITIVE.get(type);
101 }
102
103
104
105
106
107
108
109
110
111
112 public static Class<?> primitiveToWrapper(Class<?> type)
113 {
114 return PRIMITIVE_TO_WRAPPER.get(type);
115 }
116
117
118
119
120
121
122
123
124
125
126 public static boolean isPrimitive(Type type)
127 {
128
129 Class<?> clazz = getClass(type);
130 return clazz.isPrimitive();
131 }
132
133
134
135
136
137
138
139
140
141
142 public static boolean isPrimitive(String name)
143 {
144 return PRIMITIVES.contains(name);
145 }
146
147
148
149
150
151
152
153
154
155
156 public static boolean isPrimitiveWrapper(Type type)
157 {
158 return isPrimitiveWrapper(type.getTypeName());
159 }
160
161
162
163
164
165
166
167
168
169
170 public static boolean isPrimitiveWrapper(String name)
171 {
172 return WRAPPERS.contains(name);
173 }
174
175
176
177
178
179
180
181
182
183
184 public static boolean isPrimitiveArray(Type type)
185 {
186 Class<?> clazz = getClass(type);
187 return clazz.isArray() && isPrimitive(clazz.getComponentType());
188 }
189
190
191
192
193
194
195
196
197
198
199 public static boolean isInterface(Type type)
200 {
201 Class<?> clazz = getClass(type);
202 return clazz.isInterface() && !clazz.isAnnotation();
203 }
204
205
206
207
208
209
210
211
212
213
214 public static boolean isInterface(String name)
215 {
216 return isInterface(getClass(name, CLASS_LOADER));
217 }
218
219
220
221
222
223
224
225
226
227
228 public static boolean isClass(Type type)
229 {
230 Class<?> clazz = getClass(type);
231 return clazz.getSuperclass() != null || Object.class.equals(clazz);
232 }
233
234
235
236
237
238
239
240
241
242 public static void requireClass(Type type)
243 {
244 Objects.requireNonNull(type, "type cannot be null");
245 if(!isClass(type)) {
246 throw new IllegalArgumentException("type '" + type.getTypeName() + "' is not a class");
247 }
248 }
249
250
251
252
253
254
255
256
257
258
259 public static boolean isClass(String name)
260 {
261 return isClass(getClass(name, CLASS_LOADER));
262 }
263
264
265
266
267
268
269
270
271
272
273 public static Class<?> getClass(Type type)
274 {
275 return getClass(type, CLASS_LOADER);
276 }
277
278
279
280
281
282
283
284
285
286
287
288 public static Class<?> getClass(Type type, ClassLoader classLoader)
289 {
290 return type instanceof Class ? ((Class<?>) type) : getClass(type.getTypeName(), classLoader);
291 }
292
293
294
295
296
297
298
299
300
301
302
303 public static Class<?> getClass(String typeName, ClassLoader classLoader)
304 {
305 return Exceptional.apply(classLoader::loadClass, typeName);
306 }
307
308
309
310
311
312
313
314
315
316 public static void requireInterface(Type type)
317 {
318 Objects.requireNonNull(type, "type cannot be null");
319 if(!isInterface(type)) {
320 throw new IllegalArgumentException("type '" + type.getTypeName() + "' is not an interface");
321 }
322 }
323
324
325
326
327
328
329
330
331
332
333
334 public static boolean implementsAll(Class<?> type, Class<?>... interfaces)
335 {
336 return implementsAll(type, Arrays.asList(interfaces));
337
338 }
339
340
341
342
343
344
345
346
347
348
349
350 public static boolean implementsAll(Class<?> type, Collection<Class<?>> interfaces)
351 {
352 List<Class<?>> implemented = allInterfacesOf(type).collect(Collectors.toList());
353 Predicate<? super Class<?>> contained = implemented::contains;
354 return !(implemented.isEmpty() || interfaces.stream().anyMatch(contained.negate()));
355 }
356
357
358
359
360
361
362
363
364
365
366 public static Stream<Class<?>> allInterfacesOf(Class<?> type)
367 {
368 Stream<Class<?>> interfaces = Arrays.stream(type.getInterfaces());
369 return type.getSuperclass() == null ? interfaces : Stream.concat(interfaces, allInterfacesOf(type.getSuperclass()));
370 }
371
372
373
374
375
376
377
378
379
380
381
382 public static boolean extendsFrom(Class<?> type, Class<?> superType)
383 {
384 Stream<Class<?>> supers = allSuperTypesOf(type);
385 return supers.anyMatch(Predicate.isEqual(superType));
386 }
387
388
389
390
391
392
393
394
395
396
397 public static Stream<Class<?>> allSuperTypesOf(Class<?> type)
398 {
399 Stream<Class<?>> supers = Stream.of(type);
400 return type.getSuperclass() == null ? supers : Stream.concat(supers, allSuperTypesOf(type.getSuperclass()));
401 }
402 }