com.couchbase.client.deps.io.netty.util.internal.TypeParameterMatcher Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of core-io Show documentation
Show all versions of core-io Show documentation
The official Couchbase JVM Core IO Library
/*
* Copyright 2013 The Netty Project
*
* The Netty Project licenses this file to you under the Apache License,
* version 2.0 (the "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
* License for the specific language governing permissions and limitations
* under the License.
*/
package com.couchbase.client.deps.io.netty.util.internal;
import java.lang.reflect.Array;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.util.HashMap;
import java.util.Map;
public abstract class TypeParameterMatcher {
private static final TypeParameterMatcher NOOP = new NoOpTypeParameterMatcher();
private static final Object TEST_OBJECT = new Object();
public static TypeParameterMatcher get(final Class parameterType) {
final Map, TypeParameterMatcher> getCache =
InternalThreadLocalMap.get().typeParameterMatcherGetCache();
TypeParameterMatcher matcher = getCache.get(parameterType);
if (matcher == null) {
if (parameterType == Object.class) {
matcher = NOOP;
} else if (PlatformDependent.hasJavassist()) {
try {
matcher = JavassistTypeParameterMatcherGenerator.generate(parameterType);
matcher.match(TEST_OBJECT);
} catch (IllegalAccessError e) {
// Happens if parameterType is not public.
matcher = null;
} catch (Exception e) {
// Will not usually happen, but just in case.
matcher = null;
}
}
if (matcher == null) {
matcher = new ReflectiveMatcher(parameterType);
}
getCache.put(parameterType, matcher);
}
return matcher;
}
public static TypeParameterMatcher find(
final Object object, final Class parameterizedSuperclass, final String typeParamName) {
final Map, Map> findCache =
InternalThreadLocalMap.get().typeParameterMatcherFindCache();
final Class thisClass = object.getClass();
Map map = findCache.get(thisClass);
if (map == null) {
map = new HashMap();
findCache.put(thisClass, map);
}
TypeParameterMatcher matcher = map.get(typeParamName);
if (matcher == null) {
matcher = get(find0(object, parameterizedSuperclass, typeParamName));
map.put(typeParamName, matcher);
}
return matcher;
}
private static Class find0(
final Object object, Class parameterizedSuperclass, String typeParamName) {
final Class thisClass = object.getClass();
Class currentClass = thisClass;
for (;;) {
if (currentClass.getSuperclass() == parameterizedSuperclass) {
int typeParamIndex = -1;
TypeVariable[] typeParams = currentClass.getSuperclass().getTypeParameters();
for (int i = 0; i < typeParams.length; i ++) {
if (typeParamName.equals(typeParams[i].getName())) {
typeParamIndex = i;
break;
}
}
if (typeParamIndex < 0) {
throw new IllegalStateException(
"unknown type parameter '" + typeParamName + "': " + parameterizedSuperclass);
}
Type genericSuperType = currentClass.getGenericSuperclass();
if (!(genericSuperType instanceof ParameterizedType)) {
return Object.class;
}
Type[] actualTypeParams = ((ParameterizedType) genericSuperType).getActualTypeArguments();
Type actualTypeParam = actualTypeParams[typeParamIndex];
if (actualTypeParam instanceof ParameterizedType) {
actualTypeParam = ((ParameterizedType) actualTypeParam).getRawType();
}
if (actualTypeParam instanceof Class) {
return (Class) actualTypeParam;
}
if (actualTypeParam instanceof GenericArrayType) {
Type componentType = ((GenericArrayType) actualTypeParam).getGenericComponentType();
if (componentType instanceof ParameterizedType) {
componentType = ((ParameterizedType) componentType).getRawType();
}
if (componentType instanceof Class) {
return Array.newInstance((Class) componentType, 0).getClass();
}
}
if (actualTypeParam instanceof TypeVariable) {
// Resolved type parameter points to another type parameter.
TypeVariable v = (TypeVariable) actualTypeParam;
currentClass = thisClass;
if (!(v.getGenericDeclaration() instanceof Class)) {
return Object.class;
}
parameterizedSuperclass = (Class) v.getGenericDeclaration();
typeParamName = v.getName();
if (parameterizedSuperclass.isAssignableFrom(thisClass)) {
continue;
} else {
return Object.class;
}
}
return fail(thisClass, typeParamName);
}
currentClass = currentClass.getSuperclass();
if (currentClass == null) {
return fail(thisClass, typeParamName);
}
}
}
private static Class fail(Class type, String typeParamName) {
throw new IllegalStateException(
"cannot determine the type of the type parameter '" + typeParamName + "': " + type);
}
public abstract boolean match(Object msg);
private static final class ReflectiveMatcher extends TypeParameterMatcher {
private final Class type;
ReflectiveMatcher(Class type) {
this.type = type;
}
@Override
public boolean match(Object msg) {
return type.isInstance(msg);
}
}
protected TypeParameterMatcher() { }
}