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 TypeParameterMatcher() {
30 @Override
31 public boolean match(Object msg) {
32 return true;
33 }
34 };
35
36 public static TypeParameterMatcher get(final Class<?> parameterType) {
37 final Map<Class<?>, TypeParameterMatcher> getCache =
38 InternalThreadLocalMap.get().typeParameterMatcherGetCache();
39
40 TypeParameterMatcher matcher = getCache.get(parameterType);
41 if (matcher == null) {
42 if (parameterType == Object.class) {
43 matcher = NOOP;
44 } else {
45 matcher = new ReflectiveMatcher(parameterType);
46 }
47 getCache.put(parameterType, matcher);
48 }
49
50 return matcher;
51 }
52
53 public static TypeParameterMatcher find(
54 final Object object, final Class<?> parametrizedSuperclass, final String typeParamName) {
55
56 final Map<Class<?>, Map<String, TypeParameterMatcher>> findCache =
57 InternalThreadLocalMap.get().typeParameterMatcherFindCache();
58 final Class<?> thisClass = object.getClass();
59
60 Map<String, TypeParameterMatcher> map = findCache.get(thisClass);
61 if (map == null) {
62 map = new HashMap<String, TypeParameterMatcher>();
63 findCache.put(thisClass, map);
64 }
65
66 TypeParameterMatcher matcher = map.get(typeParamName);
67 if (matcher == null) {
68 matcher = get(find0(object, parametrizedSuperclass, typeParamName));
69 map.put(typeParamName, matcher);
70 }
71
72 return matcher;
73 }
74
75 private static Class<?> find0(
76 final Object object, Class<?> parametrizedSuperclass, String typeParamName) {
77
78 final Class<?> thisClass = object.getClass();
79 Class<?> currentClass = thisClass;
80 for (;;) {
81 if (currentClass.getSuperclass() == parametrizedSuperclass) {
82 int typeParamIndex = -1;
83 TypeVariable<?>[] typeParams = currentClass.getSuperclass().getTypeParameters();
84 for (int i = 0; i < typeParams.length; i ++) {
85 if (typeParamName.equals(typeParams[i].getName())) {
86 typeParamIndex = i;
87 break;
88 }
89 }
90
91 if (typeParamIndex < 0) {
92 throw new IllegalStateException(
93 "unknown type parameter '" + typeParamName + "': " + parametrizedSuperclass);
94 }
95
96 Type genericSuperType = currentClass.getGenericSuperclass();
97 if (!(genericSuperType instanceof ParameterizedType)) {
98 return Object.class;
99 }
100
101 Type[] actualTypeParams = ((ParameterizedType) genericSuperType).getActualTypeArguments();
102
103 Type actualTypeParam = actualTypeParams[typeParamIndex];
104 if (actualTypeParam instanceof ParameterizedType) {
105 actualTypeParam = ((ParameterizedType) actualTypeParam).getRawType();
106 }
107 if (actualTypeParam instanceof Class) {
108 return (Class<?>) actualTypeParam;
109 }
110 if (actualTypeParam instanceof GenericArrayType) {
111 Type componentType = ((GenericArrayType) actualTypeParam).getGenericComponentType();
112 if (componentType instanceof ParameterizedType) {
113 componentType = ((ParameterizedType) componentType).getRawType();
114 }
115 if (componentType instanceof Class) {
116 return Array.newInstance((Class<?>) componentType, 0).getClass();
117 }
118 }
119 if (actualTypeParam instanceof TypeVariable) {
120
121 TypeVariable<?> v = (TypeVariable<?>) actualTypeParam;
122 currentClass = thisClass;
123 if (!(v.getGenericDeclaration() instanceof Class)) {
124 return Object.class;
125 }
126
127 parametrizedSuperclass = (Class<?>) v.getGenericDeclaration();
128 typeParamName = v.getName();
129 if (parametrizedSuperclass.isAssignableFrom(thisClass)) {
130 continue;
131 } else {
132 return Object.class;
133 }
134 }
135
136 return fail(thisClass, typeParamName);
137 }
138 currentClass = currentClass.getSuperclass();
139 if (currentClass == null) {
140 return fail(thisClass, typeParamName);
141 }
142 }
143 }
144
145 private static Class<?> fail(Class<?> type, String typeParamName) {
146 throw new IllegalStateException(
147 "cannot determine the type of the type parameter '" + typeParamName + "': " + type);
148 }
149
150 public abstract boolean match(Object msg);
151
152 private static final class ReflectiveMatcher extends TypeParameterMatcher {
153 private final Class<?> type;
154
155 ReflectiveMatcher(Class<?> type) {
156 this.type = type;
157 }
158
159 @Override
160 public boolean match(Object msg) {
161 return type.isInstance(msg);
162 }
163 }
164
165 TypeParameterMatcher() { }
166 }