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