Replies: 14 comments
-
i tried this java.lang.reflect.TypeVariable<? extends Class<?>>[] typeParameters = context.currentClass().getTypeParameters();
StringBuilder acc = new StringBuilder();
for (int i = 0; i < typeParameters.length; i++) {
String s = new TypeContext(
GenericsResolver.resolve(
GenericsUtils.resolveClass(
new ArrayResolver(context.generic(i)).clazz,
GenericsUtils.createGenericsMap(new ArrayResolver(context.generic(i)).clazz, context.resolveGenericsOf(new ArrayResolver(context.generic(i)).clazz))
)
)
).toDetailedString(indent+1);
Class<?> g = context.generic(i);
Class<?> c = new ArrayResolver(g).clazz;
List<Class<?>> classes = context.resolveGenericsOf(c);
LinkedHashMap<String, Type> map = GenericsUtils.createGenericsMap(c, classes);
acc.append("\n");
acc.append("GENERICS MAP OF " + i + " g: " + g).append("\n");
acc.append("GENERICS MAP OF " + i + " c: " + c).append("\n");
acc.append("GENERICS MAP OF " + i + " classes: " + classes).append("\n");
acc.append("GENERICS MAP OF " + i + " map: " + map).append("\n");
acc.append("GENERICS MAP OF " + i + " r c: " + context.resolveGenericsOf(c)).append("\n");
acc.append("GENERICS MAP OF " + i + " r c: " + context.resolveType(c)).append("\n");
acc.append("GENERICS MAP OF " + i + " r c: " + context.resolveTypeGenerics(c)).append("\n");
acc.append("GENERICS MAP OF " + i + " r g: " + context.resolveGenericsOf(g)).append("\n");
acc.append("GENERICS MAP OF " + i + " r g: " + context.resolveType(g)).append("\n");
acc.append("GENERICS MAP OF " + i + " r g: " + context.resolveTypeGenerics(g)).append("\n");
extracted(acc, i, g, c, context.genericsMap());
acc.append(s);
}
printStream.println(indent(indent) + "genericParameters: " + typeParameters.length + acc);
indent--;
printStream.print(indent(indent) + "}");
printStream.flush();
return byteArrayOutputStream.toString();
}
private void extracted(StringBuilder acc, int i, Class<?> g, Class<?> c, Map<String, Type> map) {
acc.append("GENERICS MAP OF " + i + " raw c: " + GenericsResolutionUtils.resolveRawGenerics(c)).append("\n");
acc.append("GENERICS MAP OF " + i + " raw c: " + GenericsResolutionUtils.resolveGenerics(c, map)).append("\n");
acc.append("GENERICS MAP OF " + i + " raw g: " + GenericsResolutionUtils.resolveRawGenerics(g)).append("\n");
acc.append("GENERICS MAP OF " + i + " raw g: " + GenericsResolutionUtils.resolveGenerics(g, map)).append("\n");
acc.append("GENERICS MAP OF " + i + " raw c: " + GenericsUtils.resolveClass(c, map)).append("\n");
acc.append("GENERICS MAP OF " + i + " raw c: " + GenericsUtils.extractTypeGenerics(c, map)).append("\n");
acc.append("GENERICS MAP OF " + i + " raw c: " + Arrays.toString(GenericsUtils.getGenerics(c, map))).append("\n");
acc.append("GENERICS MAP OF " + i + " raw g: " + GenericsUtils.resolveClass(g, map)).append("\n");
acc.append("GENERICS MAP OF " + i + " raw g: " + GenericsUtils.extractTypeGenerics(g, map)).append("\n");
acc.append("GENERICS MAP OF " + i + " raw g: " + Arrays.toString(GenericsUtils.getGenerics(g, map))).append("\n");
} but i get this
for this
|
Beta Was this translation helpful? Give feedback.
-
"Sub" context for generic variable should be something like this: Type genericE = context.genericType("E")
// build sub context from type variable (root context used to resolve possible variables in type)
GenericsContext subContext = context.inlyingType(genericE) Basically, inlying is a type resolution knowing "context" variables (from containing class). |
Beta Was this translation helpful? Give feedback.
-
so something like this? try {
GenericsContext resolve = GenericsResolver.resolve(C__.class);
GenericsContext foo = resolve.fieldType(TypeContext.getFieldRecursive(C__.class, "foo"));
TypeContext.printDetailed(foo);
for (int i = 0; i < foo.currentClass().getTypeParameters().length; i++) {
Type type = foo.genericType(i);
while(type instanceof GenericArrayType) {
type = ((GenericArrayType) type).getGenericComponentType();
}
GenericsContext genericsContext = foo.inlyingType(type);
TypeContext.printDetailed(genericsContext);
}
} catch (NoSuchFieldException e) {
throw new RuntimeException(e);
}
|
Beta Was this translation helpful? Give feedback.
-
could be just for(Type type: foo.genericTypes())
It also could be a pure array class. Here is a few related methods from master: /**
* @param type type to check
* @return true if type is array or generic array ({@link GenericArrayType}), false otherwise.
*/
public static boolean isArray(final Type type) {
return (type instanceof Class && ((Class) type).isArray()) || type instanceof GenericArrayType;
}
/**
* For example, {@code getArrayComponentType(int[]) == int} and
* {@code getArrayComponentType(List<String>[]) == List<String>}.
*
* @param type array type (class or {@link GenericArrayType}
* @return array component type
* @throws IllegalArgumentException if provided type is not array
* @see #isArray(Type)
*/
public static Type getArrayComponentType(final Type type) {
if (!isArray(type)) {
throw new IllegalArgumentException("Provided type is not an array: "
+ TypeToStringUtils.toStringType(type));
}
if (type instanceof GenericArrayType) {
return ((GenericArrayType) type).getGenericComponentType();
} else {
return ((Class) type).getComponentType();
}
} and with it: Type type = foo.genericType(i);
while(isArray(type)) {
type = getArrayComponentType(type);
} And, just in case, when you want to get rid of context (no need deeper investigations) you could simply do: Type pureType = context.resolveType(type) This would replace possible variables in type (repackage type without variables). |
Beta Was this translation helpful? Give feedback.
-
alright, now im having a bit of trouble resolving a self-bound generic class SS1 <T extends SS1<T>> { T r; }
new TypeContext(SS1.class).findField("r").printDetailed(); public TypeContext(Type type) {
Type t = resolve(type);
if (t instanceof Class<?>) {
context = GenericsResolver.resolve((Class<?>)t);
} else {
throw new RuntimeException("resulting type is not an instance of class: " + t);
}
}
TypeContext(GenericsContext context, Type type) {
this.context = context.inlyingType(resolve(type));
}
TypeContext(GenericsContext context) {
this.context = context;
}
private Type resolve(Type type) {
while(type instanceof GenericArrayType) {
type = ((GenericArrayType) type).getGenericComponentType();
}
if (type instanceof Class<?>) {
Class<?> aClass = (Class<?>) type;
while (aClass.isArray()) {
rank++;
aClass = aClass.getComponentType();
}
return aClass;
} else {
return type;
}
}
public TypeContextField findField(String fieldName) {
try {
return new TypeContextField(this, getFieldRecursive(fieldName));
} catch (NoSuchFieldException e) {
throw new RuntimeException(e);
}
}
// ...
public static String toDetailedString(GenericsContext context, int indent) {
if (indent > 20) {
throw new RuntimeException("OVERFLOW");
}
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
PrintStream printStream = new PrintStream(byteArrayOutputStream);
printStream.println();
printStream.println(indent(indent) + "TypeContext {");
indent++;
printStream.println(indent(indent) + "type: " + context.currentClass());
StringBuilder acc = new StringBuilder();
java.lang.reflect.TypeVariable<?>[] typeParameters = context.currentClass().getTypeParameters();
for (int i = 0; i < context.currentClass().getTypeParameters().length; i++) {
acc.append(new TypeContext(context, context.genericType(i)).toDetailedString(indent+1));
}
printStream.println(indent(indent) + "genericParameters: " + typeParameters.length + acc);
indent--;
printStream.print(indent(indent) + "}");
printStream.flush();
return byteArrayOutputStream.toString();
} static class TypeContextField {
TypeContext parent;
Field field;
TypeContextField(TypeContext parent, Field field) {
this.parent = parent;
this.field = field;
}
TypeContext getReturnType() {
return new TypeContext(parent.context.fieldType(field));
}
public void printDetailed() {
System.out.println(toDetailedString());
}
public String toDetailedString() {
return toDetailedString(0);
}
private String toDetailedString(int indent) {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
PrintStream printStream = new PrintStream(byteArrayOutputStream);
printStream.println();
printStream.println(indent(indent) + "TypeContext {");
indent++;
printStream.println(indent(indent) + "field: " + field);
printStream.println(indent(indent) + "field type: " + getReturnType().toDetailedString(indent + 1));
indent--;
printStream.print(indent(indent) + "}");
printStream.flush();
return byteArrayOutputStream.toString();
}
} |
Beta Was this translation helpful? Give feedback.
-
if i just return a string instead i get
and if we print the GenericsContext as well
|
Beta Was this translation helpful? Give feedback.
-
however class SS2 extends SS1<SS2> {} correctly resolves without overflow
|
Beta Was this translation helpful? Give feedback.
-
i think we might be able to detect this by comparing the |
Beta Was this translation helpful? Give feedback.
-
ok, so now we have new TypeContext(S1.class).findField("r").printDetailed();
new TypeContext(S3.class).findField("r").printDetailed();
new TypeContext(S6.class).findField("r").printDetailed();
new TypeContext(SS1.class).findField("r").printDetailed();
new TypeContext(SS2.class).findField("r").printDetailed();
new TypeContext(S2.class).findMethods("compareTo")[0].printDetailed();
new TypeContext(GenericFields.class).findField("a").printDetailed();
new TypeContext(GenericFields.class).findMethods("aMeth")[0].printDetailed(); class GenericFields {
public List<List<String[]>[]>[] a;
public List<List<String[]>[]>[] aMeth(List<List<String[][]>[][]>[][] b) { return null; };
}
class SS1 <T extends SS1<T>> { T r; }
class SS2 extends SS1<SS2> {}
class S1 <T extends Comparable<T>> { T r; }
class CC <T> implements Comparable<T> {
@Override
public int compareTo(@NotNull T o) {
return 0;
}
}
class S3 extends S1<S2> {}
class S2 extends CC<S2> {}
class S22 extends CC<S4> {}
class S4 extends CC<S2> {}
class S5 extends S2 {}
class S6 extends S3 {}
and new TypeContext(TypeVariableBoundsSelf2.class).findMethods("setSelfBoundMethod")[0].printDetailed();
new TypeContext(TypeVariableBoundsSelf2.class).findMethods("setFoo")[0].printDetailed();
new TypeContext(TypeVariableBoundsSelf2.class).findMethods("next")[0].printDetailed();
new TypeContext(TypeVariableBoundsSelf2.class).findMethods("compareTo")[0].printDetailed(); abstract class TypeVariableBoundsSelf2 extends TypeVariableBoundsSelf<TypeVariableBoundsSelf2> implements Comparable<TypeVariableBoundsSelf2>, Iterator<TypeVariableBoundsSelf2[]> {
}
class TypeVariableBoundsSelf <X extends Comparable<X> & Iterator<X[]>> {
// public X b;
public void setFoo(X a) {
}
public X getFoo(X a) {
return null;
}
public <Y extends List<Y>> void setSelfBoundMethod (Y a) {
}
public <Y extends List<Y>> Y getSelfBoundMethod () {
return null;
}
}
|
Beta Was this translation helpful? Give feedback.
-
so yay i think it can now resolve everything correctly \o/ classes: package smallville7123.reflectui;
import static smallville7123.reflectui.TypeContext.indent;
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import java.lang.reflect.Field;
public class TypeContextField {
TypeContext parent;
Field field;
TypeContextField(TypeContext parent, Field field) {
this.parent = parent;
this.field = field;
}
TypeContext getReturnType() {
return new TypeContext(parent.context, parent.context.resolveFieldType(field));
}
public void printDetailed() {
System.out.println(toDetailedString());
}
public String toDetailedString() {
return toDetailedString(0);
}
private String toDetailedString(int indent) {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
PrintStream printStream = new PrintStream(byteArrayOutputStream);
printStream.println();
printStream.println(indent(indent) + "TypeContextField {");
indent++;
TypeContext returnType = getReturnType();
printStream.println(indent(indent) + "field: " + returnType.context.toStringCurrentClass() + " " + field.getName());
printStream.println(indent(indent) + "field type: " + returnType.toDetailedString(indent + 1));
indent--;
printStream.print(indent(indent) + "}");
printStream.flush();
return byteArrayOutputStream.toString();
}
} package smallville7123.reflectui;
import static smallville7123.reflectui.TypeContext.indent;
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import java.util.ArrayList;
import ru.vyarus.java.generics.resolver.context.MethodGenericsContext;
public class TypeContextMethod {
TypeContext parent;
MethodGenericsContext methodContext;
TypeContextMethod(TypeContext parent, MethodGenericsContext methodContext) {
this.parent = parent;
this.methodContext = methodContext;
}
TypeContext getReturnType() {
return new TypeContext(parent.context, parent.context.resolveType(methodContext.resolveReturnType()));
}
int getParameterCount() {
return methodContext.currentMethod().getParameterCount();
}
TypeContext getParameter(int position) {
return new TypeContext(methodContext.parameterType(position));
}
TypeContext[] getParameters() {
int parameterCount = methodContext.currentMethod().getParameterCount();
ArrayList<TypeContext> params = new ArrayList<>(parameterCount);
for (int i = 0; i < parameterCount; i++) {
params.add(new TypeContext(parent.context, parent.context.resolveType(methodContext.resolveParameterType(i))));
}
return params.toArray(new TypeContext[0]);
}
public void printDetailed() {
System.out.println(toDetailedString());
}
public String toDetailedString() {
return toDetailedString(0);
}
private String toDetailedString(int indent) {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
PrintStream printStream = new PrintStream(byteArrayOutputStream);
printStream.println();
printStream.println(indent(indent) + "TypeContextMethod {");
indent++;
printStream.println(indent(indent) + "method: " + methodContext.toStringMethod());
printStream.println(indent(indent) + "method return type: " + getReturnType().toDetailedString(indent + 1));
StringBuilder acc = new StringBuilder();
TypeContext[] parameters = getParameters();
for (TypeContext typeContext : parameters) {
acc.append(typeContext.toDetailedString(indent + 1));
}
printStream.println(indent(indent) + "genericParameters: " + parameters.length + acc);
indent--;
printStream.print(indent(indent) + "}");
printStream.flush();
return byteArrayOutputStream.toString();
}
} package smallville7123.reflectui;
import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import java.lang.reflect.Field;
import java.lang.reflect.GenericArrayType;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Predicate;
import ru.vyarus.java.generics.resolver.GenericsResolver;
import ru.vyarus.java.generics.resolver.context.GenericsContext;
import ru.vyarus.java.generics.resolver.context.GenericsInfo;
public class TypeContext {
GenericsContext context;
int rank = 0;
public TypeContext(Type type) {
Type t = resolve(type);
if (t instanceof Class<?>) {
context = GenericsResolver.resolve((Class<?>) t);
} else {
throw new RuntimeException("resulting type is not an instance of class: " + t);
}
}
TypeContext(GenericsContext context, Type type) {
this.context = context.inlyingType(resolve(type));
}
TypeContext(GenericsContext context) {
this.context = context;
}
private Type resolve(Type type) {
while (type instanceof GenericArrayType) {
rank++;
type = ((GenericArrayType) type).getGenericComponentType();
}
if (type instanceof Class<?>) {
Class<?> aClass = (Class<?>) type;
while (aClass.isArray()) {
rank++;
aClass = aClass.getComponentType();
}
return aClass;
} else {
return type;
}
}
public TypeContextField findField(String fieldName) {
try {
return new TypeContextField(this, getFieldRecursive(fieldName));
} catch (NoSuchFieldException e) {
throw new RuntimeException(e);
}
}
// ...
public TypeContextMethod[] findMethods(String methodName) {
try {
List<TypeContextMethod> list = new ArrayList<>();
for (Method method : getMethodsRecursive(methodName)) {
TypeContextMethod typeContextField = new TypeContextMethod(this, context.method(method));
list.add(typeContextField);
}
return list.toArray(new TypeContextMethod[0]);
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
}
}
// ...
public static String toDetailedString(TypeContext typeContext, int indent) {
if (indent > 30) {
return "<<<<OVERFLOW>>>>";
}
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
PrintStream printStream = new PrintStream(byteArrayOutputStream);
printStream.println();
printStream.println(indent(indent) + "TypeContext {");
indent++;
printStream.println(indent(indent) + "type: " + typeContext.context.currentClass());
if (typeContext.rank > 0) {
printStream.println(indent(indent) + "rank: " + typeContext.rank);
}
StringBuilder acc = new StringBuilder();
List<Type> types = typeContext.context.genericTypes();
for (Type type : types) {
if (type == typeContext.context.currentClass()) {
acc.append("\n" + indent(indent + 1) + "SELF BOUND TYPE: " + typeContext.context.currentClass() + "\n");
} else {
acc.append(new TypeContext(typeContext.context, type).toDetailedString(indent + 1));
}
}
printStream.println(indent(indent) + "genericParameters: " + types.size() + acc);
indent--;
printStream.print(indent(indent) + "}");
printStream.flush();
return byteArrayOutputStream.toString();
}
} |
Beta Was this translation helpful? Give feedback.
-
not sure if there is anything else i need to test, but i think if those work then the rest should also work as expected |
Beta Was this translation helpful? Give feedback.
-
im gonna leave this open so others can learn :) |
Beta Was this translation helpful? Give feedback.
-
ok, we can now recurse superclasses and interfaces new TypeContext(FSS3.class).findField("r").printDetailed(); // FSS2
new TypeContext(FSS3.class).findField("r").getReturnType().findMethods("compareTo")[0].printDetailed(); // FSS3
new TypeContext(FSS2.class).findMethods("compareTo")[0].printDetailed(); // FSS3 class FS1 <T> { T r; }
class FCC <T> implements Comparable<T> {
@Override
public int compareTo(@NotNull T o) {
return 0;
}
}
class FSS3 extends FS1<FSS2> {}
class FSS2 extends FCC<FSS3> {}
|
Beta Was this translation helpful? Give feedback.
-
EDIT: full code at https://github.com/mgood7123/TypeContext
im having trouble figuring out how to create a generics context from a nested generic
and i want to obtain a
GenericsContext
withinstead of
how can i do this?
Beta Was this translation helpful? Give feedback.
All reactions