Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
com.wizzardo.tools.reflection.Generic Maven / Gradle / Ivy
package com.wizzardo.tools.reflection;
import java.lang.reflect.*;
import java.util.*;
import static com.wizzardo.tools.reflection.Misc.*;
/**
* @author: wizzardo
* Date: 2/21/14
*/
public class Generic {
public final Class clazz;
public final G parent;
protected Map types;
protected F fields;
protected final G[] typeParameters;
protected Generic[] interfaces;
public static Generic of(Class clazz) {
return new Generic(clazz);
}
protected Generic(Class c, G parent, G[] typeParameters) {
this.clazz = c;
this.parent = parent;
this.typeParameters = typeParameters;
}
public Generic(Type c) {
this(c, (Map) null);
}
public Generic(Class c, Class... generics) {
clazz = c;
parent = null;
if (generics == null) {
typeParameters = createArray(0);
} else {
typeParameters = createArray(generics.length);
for (int i = 0; i < generics.length; i++) {
typeParameters[i] = create(generics[i]);
}
}
types = getTypes(c, typeParameters);
Type[] interfaces = clazz.getGenericInterfaces();
this.interfaces = createArray(interfaces.length);
initInterfaces(this.interfaces, interfaces, types, new HashMap>());
}
public Generic(Class c, G... generics) {
clazz = c;
parent = null;
if (generics == null)
typeParameters = createArray(0);
else
typeParameters = generics;
types = getTypes(c, typeParameters);
Type[] interfaces = clazz.getGenericInterfaces();
this.interfaces = createArray(interfaces.length);
initInterfaces(this.interfaces, interfaces, types, new HashMap>());
}
protected Generic(Type c, Map types) {
this(c, types, new HashMap>());
}
protected Generic(Type c, Map types, Map> cyclicDependencies) {
if (c instanceof ParameterizedType) {
ParameterizedType type = (ParameterizedType) c;
clazz = (Class) type.getRawType();
Type[] args = type.getActualTypeArguments();
TypeVariable>[] variables = clazz.getTypeParameters();
this.types = new HashMap();
this.typeParameters = createArray(args.length);
for (int i = 0; i < args.length; i++) {
this.typeParameters[i] = create(args[i], types, cyclicDependencies);
this.types.put(variables[i].getName(), this.typeParameters[i]);
}
if (clazz.getGenericSuperclass() != null)
parent = create(clazz.getGenericSuperclass(), this.types, cyclicDependencies);
else
parent = null;
types = this.types;
} else if (c instanceof TypeVariable) {
if (types != null) {
TypeVariable variable = (TypeVariable) c;
G g = types.get(variable.getName());
if (g == null) {
Type type = variable.getBounds()[0];
g = create(type, types, cyclicDependencies);
}
clazz = g.clazz;
parent = (G) g.parent;
typeParameters = (G[]) g.typeParameters;
interfaces = g.interfaces;
this.types = g.types;
return;
} else {
clazz = (Class) Object.class;
parent = null;
typeParameters = createArray(0);
}
} else if (c instanceof GenericArrayType) {
parent = null;
clazz = (Class) Array.class;
typeParameters = createArray(1);
typeParameters[0] = create(((GenericArrayType) c).getGenericComponentType());
} else if (c instanceof WildcardType) {
WildcardType wildcardType = (WildcardType) c;
Type type = wildcardType.getLowerBounds().length > 0 ? wildcardType.getLowerBounds()[0] : wildcardType.getUpperBounds()[0];
Generic g = create(type);
clazz = g.clazz;
typeParameters = g.typeParameters;
parent = g.parent;
interfaces = g.interfaces;
return;
} else {
Class cl = (Class) c;
if (cl.isArray()) {
clazz = (Class) Array.class;
typeParameters = createArray(1);
typeParameters[0] = create(cl.getComponentType());
parent = null;
interfaces = new Generic[0];
return;
}
Generic cd = cyclicDependencies.get(cl);
if (cd != null) {
clazz = cd.clazz;
parent = cd.parent;
interfaces = cd.interfaces;
typeParameters = cd.typeParameters;
return;
}
clazz = cl;
this.typeParameters = createArray(0);
if (!clazz.isEnum() && clazz.getGenericSuperclass() != null)
parent = create(clazz.getGenericSuperclass(), types, cyclicDependencies);
else
parent = null;
cyclicDependencies.put(cl, this);
}
Type[] interfaces = clazz.getGenericInterfaces();
this.interfaces = createArray(interfaces.length);
initInterfaces(this.interfaces, interfaces, types, cyclicDependencies);
}
protected void initInterfaces(Generic[] result, Type[] interfaces, Map types, Map> cyclicDependencies) {
for (int i = 0; i < interfaces.length; i++) {
result[i] = create(interfaces[i], types, cyclicDependencies);
}
}
private Map getTypes(Class c, G[] generics) {
TypeVariable>[] variables = c.getTypeParameters();
if (variables.length == 0 || generics.length == 0)
return null;
Map types = new HashMap();
for (int i = 0; i < variables.length && i < generics.length; i++) {
types.put(variables[i].getName(), generics[i]);
}
return types;
}
public int typesCount() {
return typeParameters.length;
}
public int getTypesCount() {
return typesCount();
}
public G type(int i) {
return typeParameters[i];
}
public G getType(int i) {
return type(i);
}
public G type(String name) {
return types.get(name);
}
public G getType(String name) {
return type(name);
}
public Map types() {
if (types == null)
return Collections.emptyMap();
return Collections.unmodifiableMap(types);
}
public Map getTypes() {
return types();
}
public int getInterfacesCount() {
return interfaces.length;
}
public Generic getInterface(int i) {
return interfaces[i];
}
@Override
public String toString() {
if (typesCount() == 0)
return clazz.getSimpleName();
return join(new StringBuilder(32)
.append(clazz.getSimpleName())
.append('<'),
typeParameters, ",")
.append('>')
.toString();
}
public G getGenericType(Field f) {
Generic g = this;
while (g != null && g.clazz != f.getDeclaringClass()) {
g = g.parent;
}
if (g != null && f.getGenericType() instanceof TypeVariable) {
return (G) g.types.get(((TypeVariable) f.getGenericType()).getName());
}
return null;
}
public F getFields() {
if (fields != null)
return fields;
fields = (F) new Fields(this);
return fields;
}
protected G[] createArray(int size) {
return (G[]) new Generic[size];
}
protected G create(Type c) {
return (G) new Generic(c);
}
protected G create(Class c, Class... generics) {
return (G) new Generic(c, generics);
}
protected G create(Type c, Map types) {
return (G) new Generic(c, types);
}
protected G create(Type c, Map types, Map> cyclicDependencies) {
return (G) new Generic(c, types, cyclicDependencies);
}
public G parent() {
return parent;
}
public List methods() {
List methods = new ArrayList();
fillMethods(methods, this);
return methods;
}
protected void fillMethods(List methods, Generic generic) {
Method[] declaredMethods = generic.clazz.getDeclaredMethods();
for (Method method : declaredMethods) {
Generic returnType = new Generic(method.getGenericReturnType(), generic.types);
Type[] genericParameterTypes = method.getGenericParameterTypes();
List args = new ArrayList(genericParameterTypes.length);
for (Type genericParameterType : genericParameterTypes) {
args.add(new Generic(genericParameterType, generic.types));
}
methods.add(new GenericMethod(method, returnType, Collections.unmodifiableList(args)));
}
for (Generic g : generic.interfaces) {
fillMethods(methods, g);
}
if (generic.parent != null)
fillMethods(methods, generic.parent);
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Generic, ?, ?> generic = (Generic, ?, ?>) o;
if (!clazz.equals(generic.clazz)) return false;
return Arrays.equals(typeParameters, generic.typeParameters);
}
@Override
public int hashCode() {
int result = clazz.hashCode();
result = 31 * result + Arrays.hashCode(typeParameters);
return result;
}
}