io.kroxylicious.proxy.config.model.Visitors Maven / Gradle / Ivy
package io.kroxylicious.proxy.config.model;
import java.util.Optional;
import java.util.ArrayList;
import java.lang.String;
import java.lang.reflect.GenericArrayType;
import java.util.LinkedHashMap;
import java.lang.reflect.Array;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;
import java.lang.Class;
import java.util.List;
import java.util.Arrays;
import java.util.Map;
public final class Visitors{
private Visitors() {
//Utility Class
}
public static Visitor newVisitor(Class type,Visitor visitor) {
return new DelegatingVisitor(type, visitor);
}
protected static List getTypeArguments(Class baseClass,Class extends T> childClass) {
Map resolvedTypes = new LinkedHashMap();
Type type = childClass;
// start walking up the inheritance hierarchy until we hit baseClass
for (Class cl = getClass(type); cl != null && cl != Object.class
&& !baseClass.getName().equals(cl.getName()); cl = getClass(type)) {
if (type instanceof Class) {
Class c = (Class) type;
Optional nextInterface = baseClass.isInterface() ? getMatchingInterface(baseClass, c.getGenericInterfaces())
: Optional.empty();
if (nextInterface.isPresent()) {
type = nextInterface.get();
} else {
// there is no useful information for us in raw types, so just keep going.
type = ((Class) type).getGenericSuperclass();
}
} else if (type instanceof ParameterizedType) {
ParameterizedType parameterizedType = (ParameterizedType) type;
Type t = parameterizedType.getRawType();
if (t instanceof Class) {
Class> rawType = (Class) parameterizedType.getRawType();
Type[] actualTypeArguments = parameterizedType.getActualTypeArguments();
TypeVariable>[] typeParameters = rawType.getTypeParameters();
for (int i = 0; i < actualTypeArguments.length; i++) {
resolvedTypes.put(typeParameters[i], actualTypeArguments[i]);
}
if (!baseClass.equals(rawType)) {
type = rawType.getGenericSuperclass();
}
} else {
break;
}
}
}
// finally, for each actual type argument provided to baseClass, determine (if possible)
// the raw class for that type argument.
Type[] actualTypeArguments;
if (type instanceof Class) {
actualTypeArguments = ((Class) type).getTypeParameters();
} else {
actualTypeArguments = ((ParameterizedType) type).getActualTypeArguments();
}
List typeArgumentsAsClasses = new ArrayList();
// resolve types by chasing down type variables.
for (Type baseType : actualTypeArguments) {
while (resolvedTypes.containsKey(baseType)) {
baseType = resolvedTypes.get(baseType);
}
typeArgumentsAsClasses.add(getClass(baseType));
}
return typeArgumentsAsClasses;
}
private static String getRawName(Type type) {
return type instanceof ParameterizedType ? ((ParameterizedType) type).getRawType().getTypeName() : type.getTypeName();
}
private static Class> getClass(Type type) {
if (type instanceof Class) {
return (Class) type;
} else if (type instanceof ParameterizedType) {
return getClass(((ParameterizedType) type).getRawType());
} else if (type instanceof GenericArrayType) {
Type componentType = ((GenericArrayType) type).getGenericComponentType();
Class> componentClass = getClass(componentType);
if (componentClass != null) {
return Array.newInstance(componentClass, 0).getClass();
} else {
return null;
}
} else {
return null;
}
}
private static Optional getMatchingInterface(Class> targetInterface,java.lang.reflect.Type... candidates) {
if (candidates == null || candidates.length == 0) {
return Optional.empty();
}
Optional match = Arrays.stream(candidates).filter(c -> getRawName(c).equals(targetInterface.getTypeName()))
.findFirst();
if (match.isPresent()) {
return match;
} else {
for (Type candidate : candidates) {
if (candidate instanceof Class) {
Class c = (Class) candidate;
Optional next = getMatchingInterface(targetInterface, c.getGenericInterfaces());
if (next.isPresent()) {
return Optional.of(c);
}
}
}
return Optional.empty();
}
}
}