1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package io.netty5.util.internal;
18
19 import io.netty5.util.concurrent.FastThreadLocal;
20
21 import java.lang.reflect.Array;
22 import java.lang.reflect.GenericArrayType;
23 import java.lang.reflect.ParameterizedType;
24 import java.lang.reflect.Type;
25 import java.lang.reflect.TypeVariable;
26 import java.util.HashMap;
27 import java.util.IdentityHashMap;
28 import java.util.Map;
29
30 public abstract class TypeParameterMatcher {
31
32 private static final FastThreadLocal<Map<Class<?>, TypeParameterMatcher>> TYPE_MATCHER_GET_CACHE =
33 new FastThreadLocal<>() {
34 @Override
35 protected Map<Class<?>, TypeParameterMatcher> initialValue() {
36 return new IdentityHashMap<>();
37 }
38 };
39
40 private static final FastThreadLocal<Map<Class<?>, Map<String, TypeParameterMatcher>>> TYPE_MATCHER_FIND_CACHE =
41 new FastThreadLocal<>() {
42 @Override
43 protected Map<Class<?>, Map<String, TypeParameterMatcher>> initialValue() {
44 return new IdentityHashMap<>();
45 }
46 };
47
48 private static final TypeParameterMatcher NOOP = new TypeParameterMatcher() {
49 @Override
50 public boolean match(Object msg) {
51 return true;
52 }
53 };
54
55 public static TypeParameterMatcher get(final Class<?> parameterType) {
56 final Map<Class<?>, TypeParameterMatcher> getCache = TYPE_MATCHER_GET_CACHE.get();
57
58 TypeParameterMatcher matcher = getCache.get(parameterType);
59 if (matcher == null) {
60 if (parameterType == Object.class) {
61 matcher = NOOP;
62 } else {
63 matcher = new ReflectiveMatcher(parameterType);
64 }
65 getCache.put(parameterType, matcher);
66 }
67
68 return matcher;
69 }
70
71 public static TypeParameterMatcher find(
72 final Object object, final Class<?> parametrizedSuperclass, final String typeParamName) {
73
74 final Map<Class<?>, Map<String, TypeParameterMatcher>> findCache = TYPE_MATCHER_FIND_CACHE.get();
75 final Class<?> thisClass = object.getClass();
76
77 Map<String, TypeParameterMatcher> map = findCache.computeIfAbsent(thisClass, k -> new HashMap<>());
78
79 TypeParameterMatcher matcher = map.get(typeParamName);
80 if (matcher == null) {
81 matcher = get(find0(object, parametrizedSuperclass, typeParamName));
82 map.put(typeParamName, matcher);
83 }
84
85 return matcher;
86 }
87
88 private static Class<?> find0(
89 final Object object, Class<?> parametrizedSuperclass, String typeParamName) {
90
91 final Class<?> thisClass = object.getClass();
92 Class<?> currentClass = thisClass;
93 for (;;) {
94 if (currentClass.getSuperclass() == parametrizedSuperclass) {
95 int typeParamIndex = -1;
96 TypeVariable<?>[] typeParams = currentClass.getSuperclass().getTypeParameters();
97 for (int i = 0; i < typeParams.length; i ++) {
98 if (typeParamName.equals(typeParams[i].getName())) {
99 typeParamIndex = i;
100 break;
101 }
102 }
103
104 if (typeParamIndex < 0) {
105 throw new IllegalStateException(
106 "unknown type parameter '" + typeParamName + "': " + parametrizedSuperclass);
107 }
108
109 Type genericSuperType = currentClass.getGenericSuperclass();
110 if (!(genericSuperType instanceof ParameterizedType)) {
111 return Object.class;
112 }
113
114 Type[] actualTypeParams = ((ParameterizedType) genericSuperType).getActualTypeArguments();
115
116 Type actualTypeParam = actualTypeParams[typeParamIndex];
117 if (actualTypeParam instanceof ParameterizedType) {
118 actualTypeParam = ((ParameterizedType) actualTypeParam).getRawType();
119 }
120 if (actualTypeParam instanceof Class) {
121 return (Class<?>) actualTypeParam;
122 }
123 if (actualTypeParam instanceof GenericArrayType) {
124 Type componentType = ((GenericArrayType) actualTypeParam).getGenericComponentType();
125 if (componentType instanceof ParameterizedType) {
126 componentType = ((ParameterizedType) componentType).getRawType();
127 }
128 if (componentType instanceof Class) {
129 return Array.newInstance((Class<?>) componentType, 0).getClass();
130 }
131 }
132 if (actualTypeParam instanceof TypeVariable) {
133
134 TypeVariable<?> v = (TypeVariable<?>) actualTypeParam;
135 if (!(v.getGenericDeclaration() instanceof Class)) {
136 return Object.class;
137 }
138
139 currentClass = thisClass;
140 parametrizedSuperclass = (Class<?>) v.getGenericDeclaration();
141 typeParamName = v.getName();
142 if (parametrizedSuperclass.isAssignableFrom(thisClass)) {
143 continue;
144 }
145 return Object.class;
146 }
147
148 return fail(thisClass, typeParamName);
149 }
150 currentClass = currentClass.getSuperclass();
151 if (currentClass == null) {
152 return fail(thisClass, typeParamName);
153 }
154 }
155 }
156
157 private static Class<?> fail(Class<?> type, String typeParamName) {
158 throw new IllegalStateException(
159 "cannot determine the type of the type parameter '" + typeParamName + "': " + type);
160 }
161
162 public abstract boolean match(Object msg);
163
164 private static final class ReflectiveMatcher extends TypeParameterMatcher {
165 private final Class<?> type;
166
167 ReflectiveMatcher(Class<?> type) {
168 this.type = type;
169 }
170
171 @Override
172 public boolean match(Object msg) {
173 return type.isInstance(msg);
174 }
175 }
176
177 TypeParameterMatcher() { }
178 }