xvik / generics-resolver

Java generics runtime resolver
https://xvik.github.io/generics-resolver
MIT License
46 stars 9 forks source link

help with iterating generics recursively #26

Closed mgood7123 closed 1 year ago

mgood7123 commented 1 year ago

how would i go about iterating resolved generics recursively?

specifically my intent is to provide hierarchical type information, leveraging Generics Resolver to do the hard work for me

(cus i tried and failed many times to manually resolve generics, fix one thing and something breaks somewhere else, fix that and something else breaks, qwq)

for example

// List<List<String[]>[]> a;

field: a ( with return type: List<List<String[]>[]> )
return type:
{
    type: List
    generic parameters: 1
    {
        {
            type: List
            rank: 1
            generic parameters: 1
            {
                {
                    type: String
                    rank: 1
                }
            }
        }
    }
}
class Foo <T> {
    List<List<String[]>[]> a(boolean r, T z);
}
foo<HashMap<Integer, Pair<Object, ArrayList<Float>>> example;
method: a ( with return type: List<List<String[]>[]> ), ( with parameters: boolean, HashMap<Integer, Pair<Object, ArrayList<Float>>> )
return type:
{
    type: List
    generic parameters: 1
    {
        {
            type: List
            rank: 1
            generic parameters: 1
            {
                {
                    type: String
                    rank: 1
                }
            }
        }
    }
    method parameters: 1
    {
        {
            type: boolean
        },
        {
            type: HashMap
            generic parameters: 2
            {
                {
                    type: Integer
                    rank: 1
                },
                {
                    type: Pair
                    generic parameters: 2
                    {
                        {
                            type: Object
                        },
                        {
                            type: ArrayList
                            generic parameters: 1
                            {
                                {
                                    type: Float
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}

specifically, with my old library i could do:

give it

class C__ <T extends java.io.Serializable> {
    private List<HashMap<T[][], Pair<T[], C__<StringBuilder>>>[]> foo;
}
try {
    // get the field of new C__<Serializable>().foo.get(0)[0].values().iterator().next().second
    TypeInfo foo = TypeInfo.getFieldRecursive(C__.class, "foo");
    for (TypeInfo foo2 : TypeInfo.getMethodsRecursive(foo.getReturnType(), "get")) {
        for (TypeInfo foo3 : TypeInfo.getMethodsRecursive(foo2.getReturnType(), "values")) {
            for (TypeInfo foo4 : TypeInfo.getMethodsRecursive(foo3.getReturnType(), "iterator")) {
                for (TypeInfo foo5 : TypeInfo.getMethodsRecursive(foo4.getReturnType(), "next")) {
                    TypeInfo foo6 = TypeInfo.getFieldRecursive(foo5.getReturnType(), "second");
                    // get the field of new C__<StringBuilder>().foo.get(0)[0].values().iterator().next().first
                    TypeInfo foo7 = TypeInfo.getFieldRecursive(foo6.getReturnType(), "foo");
                    foo7.printDetailed();
                    for (TypeInfo foo8 : TypeInfo.getMethodsRecursive(foo7.getReturnType(), "get")) {
                        for (TypeInfo foo9 : TypeInfo.getMethodsRecursive(foo8.getReturnType(), "values")) {
                            for (TypeInfo foo10 : TypeInfo.getMethodsRecursive(foo9.getReturnType(), "iterator")) {
                                for (TypeInfo foo11 : TypeInfo.getMethodsRecursive(foo10.getReturnType(), "next")) {
                                    TypeInfo foo12 = TypeInfo.getFieldRecursive(foo11.getReturnType(), "first");
                                    foo12.printDetailed();
                                }
                            }
                        }
                    }
                }
            }
        }
    }
} catch (NoSuchMethodException | NoSuchFieldException e) {
    throw new RuntimeException(e);
}

and it outputs

TypeInfo {
  field: private smallville7123.Main.C__#foo ( with return type: public abstract interface java.util.List<public java.util.HashMap<public final java.lang.StringBuilder[][], public smallville7123.reflectui.utils.Pair<public final java.lang.StringBuilder[], internal smallville7123.Main.C__<public final java.lang.StringBuilder>>>[]> )
  field type: 
    TypeInfo {
      type: public abstract interface java.util.List<public java.util.HashMap<public final java.lang.StringBuilder[][], public smallville7123.reflectui.utils.Pair<public final java.lang.StringBuilder[], internal smallville7123.Main.C__<public final java.lang.StringBuilder>>>[]>
      isGeneric: true
      genericParameters: 1
        TypeInfo {
          type: public java.util.HashMap<public final java.lang.StringBuilder[][], public smallville7123.reflectui.utils.Pair<public final java.lang.StringBuilder[], internal smallville7123.Main.C__<public final java.lang.StringBuilder>>>[]
          isGeneric: true
          typeRank: 1
          genericParameters: 2
            TypeInfo {
              type: public final java.lang.StringBuilder[][]
              typeRank: 2
            }
            TypeInfo {
              type: public smallville7123.reflectui.utils.Pair<public final java.lang.StringBuilder[], internal smallville7123.Main.C__<public final java.lang.StringBuilder>>
              isGeneric: true
              genericParameters: 2
                TypeInfo {
                  type: public final java.lang.StringBuilder[]
                  typeRank: 1
                }
                TypeInfo {
                  type: internal smallville7123.Main.C__<public final java.lang.StringBuilder>
                  isGeneric: true
                  genericParameters: 1
                    TypeInfo {
                      type: public final java.lang.StringBuilder
                    }
                }
            }
        }
    }
}
TypeInfo {
  field: public smallville7123.reflectui.utils.Pair#first ( with return type: public final java.lang.StringBuilder )
  field type: 
    TypeInfo {
      type: public final java.lang.StringBuilder
    }
}

and

class GenericFields {
    public Pair<Pair<Pair<Integer, Boolean>[][], Pair<Integer, Boolean>[][]>[][], Pair<Pair<Integer, Boolean>[][], Pair<Integer, Boolean>[][]>[][]>[][] integerBooleanPairMulti;
}
                    addFieldTest(m, "matches", GenericFields.class, "integerBooleanPairMulti", f -> {
                        TypeInfo ret = f.second.getReturnType();
                        MicroTest.ExpectObjectValuesEquals(ret.getType(), Pair.class);
                        TypeInfo LHS1 = ret.getGenericParameters().get(0);
                        MicroTest.ExpectObjectValuesEquals(LHS1.getType(), Pair.class);
                        TypeInfo LHS2 = LHS1.getGenericParameters().get(0);
                        MicroTest.ExpectObjectValuesEquals(LHS2.getType(), Pair.class);
                        TypeInfo LHS3 = LHS2.getGenericParameters().get(0);
                        MicroTest.ExpectObjectValuesEquals(LHS3.getType(), Integer.class);
                        TypeInfo LHS4 = LHS2.getGenericParameters().get(1);
                        MicroTest.ExpectObjectValuesEquals(LHS4.getType(), Boolean.class);
                        TypeInfo LHS5 = LHS1.getGenericParameters().get(0);
                        MicroTest.ExpectObjectValuesEquals(LHS5.getType(), Pair.class);
                        TypeInfo LHS6 = LHS2.getGenericParameters().get(0);
                        MicroTest.ExpectObjectValuesEquals(LHS6.getType(), Integer.class);
                        TypeInfo LHS7 = LHS2.getGenericParameters().get(1);
                        MicroTest.ExpectObjectValuesEquals(LHS7.getType(), Boolean.class);
                        TypeInfo RHS1 = ret.getGenericParameters().get(0);
                        MicroTest.ExpectObjectValuesEquals(RHS1.getType(), Pair.class);
                        TypeInfo RHS2 = RHS1.getGenericParameters().get(0);
                        MicroTest.ExpectObjectValuesEquals(RHS2.getType(), Pair.class);
                        TypeInfo RHS3 = RHS2.getGenericParameters().get(0);
                        MicroTest.ExpectObjectValuesEquals(RHS3.getType(), Integer.class);
                        TypeInfo RHS4 = RHS2.getGenericParameters().get(1);
                        MicroTest.ExpectObjectValuesEquals(RHS4.getType(), Boolean.class);
                        TypeInfo RHS5 = RHS1.getGenericParameters().get(0);
                        MicroTest.ExpectObjectValuesEquals(RHS5.getType(), Pair.class);
                        TypeInfo RHS6 = RHS2.getGenericParameters().get(0);
                        MicroTest.ExpectObjectValuesEquals(RHS6.getType(), Integer.class);
                        TypeInfo RHS7 = RHS2.getGenericParameters().get(1);
                        MicroTest.ExpectObjectValuesEquals(RHS7.getType(), Boolean.class);
                    });

and i am wondering how i could replicate most of this functionality with Generics Resolver