-
-
Notifications
You must be signed in to change notification settings - Fork 201
Expand file tree
/
Copy pathReified.java
More file actions
292 lines (265 loc) · 7.94 KB
/
Copy pathReified.java
File metadata and controls
292 lines (265 loc) · 7.94 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
/*
* Jooby https://jooby.io
* Apache License Version 2.0 https://jooby.io/LICENSE.txt
* Copyright 2014 Edgar Espina
*/
package io.jooby;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.CompletableFuture;
import io.jooby.internal.reflect.$Types;
/**
* Represents a generic type {@code T}. Java doesn't yet provide a way to represent generic types,
* so this class does. Forces clients to create a subclass of this class which enables retrieval the
* type information even at runtime.
*
* <p>For example, to create a type literal for {@code List<String>}, you can create an empty
* anonymous inner class:
*
* <p>{@code Reified<List<String>> list = new Reified<List<String>>() {};}
*
* <p>This syntax cannot be used to create type literals that have wildcard parameters, such as
* {@code Class<?>} or {@code List<? extends CharSequence>}.
*
* @param <T> Target type.
* @author Bob Lee
* @author Sven Mawson
* @author Jesse Wilson
*/
public class Reified<T> {
@SuppressWarnings("rawtypes")
private final Class rawType;
private final Type type;
private final int hashCode;
/**
* Constructs a new type literal. Derives represented class from type parameter.
*
* <p>Clients create an empty anonymous subclass. Doing so embeds the type parameter in the
* anonymous class's type hierarchy so we can reconstitute it at runtime despite erasure.
*/
@SuppressWarnings("unchecked")
public Reified() {
this.type = getSuperclassTypeParameter(getClass());
this.rawType = (Class<? super T>) $Types.getRawType(type);
this.hashCode = type.hashCode();
}
/**
* Unsafe. Constructs a type literal manually.
*
* @param type Generic type.
*/
private Reified(Type type) {
this.type = $Types.canonicalize(type);
this.rawType = $Types.getRawType(this.type);
this.hashCode = this.type.hashCode();
}
/**
* Unsafe. Constructs a type literal manually.
*
* @param type Generic type.
*/
@SuppressWarnings("rawtypes")
private Reified(Class type) {
this.type = type;
this.rawType = type;
this.hashCode = type.hashCode();
}
/**
* Returns the type from super class's type parameter in {@link $Types#canonicalize canonical
* form}.
*
* @param subclass Subclass.
* @return Type.
*/
private static Type getSuperclassTypeParameter(Class<?> subclass) {
Type superclass = subclass.getGenericSuperclass();
if (superclass instanceof Class) {
throw new RuntimeException("Missing type parameter.");
}
ParameterizedType parameterized = (ParameterizedType) superclass;
return $Types.canonicalize(parameterized.getActualTypeArguments()[0]);
}
/**
* Returns the raw (non-generic) type for this type.
*
* @return Returns the raw (non-generic) type for this type.
*/
public final Class<? super T> getRawType() {
return rawType;
}
/**
* Gets underlying {@code Type} instance.
*
* @return Gets underlying {@code Type} instance.
*/
public final Type getType() {
return type;
}
@Override
public final int hashCode() {
return this.hashCode;
}
@Override
public final boolean equals(Object o) {
return o instanceof Reified<?> && $Types.equals(type, ((Reified<?>) o).type);
}
@Override
public final String toString() {
return $Types.typeToString(type);
}
/**
* Gets type literal for the given {@code Type} instance.
*
* @param type Source type.
* @return Gets type literal for the given {@code Type} instance.
*/
public static Reified<?> get(Type type) {
return new Reified<>(type);
}
/**
* Get raw type (class) from given type.
*
* @param type Type.
* @return Raw type.
*/
public static Class<?> rawType(Type type) {
if (type instanceof Class) {
return (Class<?>) type;
}
return new Reified<>(type).rawType;
}
/**
* Gets type literal for the given {@code Class} instance.
*
* @param type Java type.
* @param <T> Generic type.
* @return Gets type literal for the given {@code Class} instance.
*/
public static <T> Reified<T> get(Class<T> type) {
return new Reified<>(type);
}
/**
* Creates a {@link List} type literal.
*
* @param type Item type.
* @param <T> Item type.
* @return A {@link List} type literal.
*/
public static <T> Reified<List<T>> list(Type type) {
return getParameterized(List.class, type);
}
/**
* Creates a {@link List} type literal.
*
* @param type Item type.
* @param <T> Item type.
* @return A {@link List} type literal.
*/
public static <T> Reified<List<T>> list(Reified<T> type) {
return getParameterized(List.class, type.getType());
}
/**
* Creates a {@link Set} type literal.
*
* @param type Item type.
* @param <T> Item type.
* @return A {@link Set} type literal.
*/
public static <T> Reified<Set<T>> set(Type type) {
return getParameterized(Set.class, type);
}
/**
* Creates a {@link Set} type literal.
*
* @param type Item type.
* @param <T> Item type.
* @return A {@link Set} type literal.
*/
public static <T> Reified<Set<T>> set(Reified<T> type) {
return getParameterized(Set.class, type.getType());
}
/**
* Creates an {@link Optional} type literal.
*
* @param type Item type.
* @param <T> Item type.
* @return A {@link Optional} type literal.
*/
public static <T> Reified<Optional<T>> optional(Type type) {
return getParameterized(Optional.class, type);
}
/**
* Creates an {@link Optional} type literal.
*
* @param type Item type.
* @param <T> Item type.
* @return A {@link Optional} type literal.
*/
public static <T> Reified<Optional<T>> optional(Reified<T> type) {
return getParameterized(Optional.class, type.getType());
}
/**
* Creates an {@link Map} type literal.
*
* @param key Key type.
* @param value Value type.
* @param <K> Key type.
* @param <V> Key type.
* @return A {@link Map} type literal.
*/
public static <K, V> Reified<Map<K, V>> map(Type key, Type value) {
return getParameterized(Map.class, key, value);
}
/**
* Creates an {@link Map} type literal.
*
* @param key Key type.
* @param value Value type.
* @param <K> Key type.
* @param <V> Key type.
* @return A {@link Map} type literal.
*/
public static <K, V> Reified<Map<K, V>> map(Reified<K> key, Reified<V> value) {
return getParameterized(Map.class, key.getType(), value.getType());
}
/**
* Creates a {@link CompletableFuture} type literal.
*
* @param type Item type.
* @param <T> Item type.
* @return A {@link CompletableFuture} type literal.
*/
public static <T> Reified<CompletableFuture<T>> completableFuture(Type type) {
return getParameterized(CompletableFuture.class, type);
}
/**
* Gets type literal for the parameterized type represented by applying {@code typeArguments} to
* {@code rawType}.
*
* @param rawType Raw type.
* @param typeArguments Parameter types.
* @param <T> Target type.
* @return Gets type literal for the parameterized type represented by applying {@code
* typeArguments} to {@code rawType}.
*/
public static <T> Reified<T> getParameterized(Type rawType, Type... typeArguments) {
return new Reified<>($Types.newParameterizedTypeWithOwner(null, rawType, typeArguments));
}
/**
* Gets type literal for the parameterized type represented by applying {@code typeArguments} to
* {@code rawType}.
*
* @param rawType Raw type.
* @param argument Parameter types.
* @param <T> Target type.
* @return Gets type literal for the parameterized type represented by applying {@code
* typeArguments} to {@code rawType}.
*/
public static <T> Reified<T> getParameterized(Type rawType, Reified<?> argument) {
return new Reified<>($Types.newParameterizedTypeWithOwner(null, rawType, argument.getType()));
}
}