0

I am using google guava library to get all the classes recursively from the packages mentioned and iterating through all the public methods and getting their parameters. the "mapOfpackageMethodParameters" will be then passed to gson object which will give me json.

Is there any way i can optimize the two innermost for loops by using lambdas or java8 stream api. any other suggestions ??

String[] packagenames = { "com.example" };
LinkedHashMap<String, LinkedHashMap<String, LinkedHashMap<String, String>>> mapOfpackageMethodParameters = new LinkedHashMap<>();
for (String packagename : packagenames) {
    List<ClassInfo> clazzList = ClassPath.from(ClassLoader.getSystemClassLoader())
            .getTopLevelClassesRecursive(packagename).stream().filter(c -> c.getPackageName().endsWith("test"))
            .collect(Collectors.toList());
    for (ClassInfo class1 : clazzList) {
        List<Method> methodList = Arrays.asList(Class.forName(class1.getName()).getMethods());
        LinkedHashMap<String, LinkedHashMap<String, String>> methodMap = new LinkedHashMap<>();
        for (Method method : methodList) {
            List<Parameter> parameterList = Arrays.asList(method.getParameters());
            LinkedHashMap<String, String> parameterMap = parameterList.stream()
                    .collect(Collectors.toMap(param -> param.getName(), param -> param.getType().toString(),
                            (x, y) -> x, LinkedHashMap::new));
            methodMap.put(method.getName(), parameterMap);
        }
        mapOfpackageMethodParameters.put(class1.getName(), methodMap);
    }
}

this is the final json that is expected and generated from the above code.

{
    "com.example.test.dummyclass": {
        "sampletest1": {
            "dummyargument1": "class java.lang.String",
            "dummyargument2": "class java.lang.String"
        },
        "sampletest2": {
            "dummyargument1": "class java.lang.String",
            "dummyargument2": "class java.lang.Integer"
        }
    }
}
  • 1
    Do you want to *optimize* this for performance or *optimize* this from the point of view of code complexity? – Chetan Kinger Feb 04 '17 at 07:58
  • optimize the complexity mostly. by the way performance can be improved by using parallelStream right?? – Suhail Sullad Feb 04 '17 at 08:18
  • Write intermediary methods. Your code is barely legible because you put too much in a single place. If you're planning to return all that as a gson object, I'd strongly suggest you write specific objects that need to be returned like `PackageJson`, `ClassJson`, `MethodJson`. Those objects would then be transformed by Gson automatically. Removing maps is already a huge step in reducing your complexity because you have less generics which make the whole stuff illegible. – Olivier Grégoire Feb 04 '17 at 15:27
  • @OlivierGrégoire thanks for the suggestion. But i already tried it and that code was taking too much time to generate a json file with same input. So i had to scrap that and rewrite into this. Its better performing than the previous solution that i had in mind. – Suhail Sullad Feb 04 '17 at 15:58
  • @SuhailSullad using `parallelStream()` will usually hurt, not help, performance. Parallelism has overhead that is only worthwhile for _very, very big_ pieces of data or _very, very big_ operations. This is not going to be big enough. – Louis Wasserman Feb 04 '17 at 17:36
  • @LouisWasserman yes that what i reckoned later. parallelStream() was not helping even for more than 200 classes with atleast 50 methods. – Suhail Sullad Feb 04 '17 at 18:06

1 Answers1

0

You can convert each of the for..each loops into a stream which collects into a LinkedHashMap. Making the entire operation very functional.

String[] packageNames = { "com.example" };
LinkedHashMap<String, LinkedHashMap<String, LinkedHashMap<String, String>>> mapOfpackageMethodParameters = Arrays
    .stream(packageNames)
    .flatMap(packageName -> ClassPath
        .from(ClassLoader.getSystemClassLoader())
        .getTopLevelClassesRecursive(packageName)
        .stream())
    .filter(classInfo -> classInfo.getPackageName().endsWith("test"))
    .map(ClassInfo::load)
    .collect(Collectors.toMap(
        Class::getName,
        clazz -> Arrays
            .stream(clazz.getMethods())
            .collect(Collectors.toMap(
                Method::getName,
                method -> Arrays
                    .stream(method.getParameters())
                    .collect(Collectors.toMap(
                        Parameter::getName,
                        param -> param.getType().toString(),
                        (x, y) -> x, LinkedHashMap::new)),
                (x, y) -> x, LinkedHashMap::new)),
        (x, y) -> x, LinkedHashMap::new));
4castle
  • 32,613
  • 11
  • 69
  • 106
  • Awesome but doesn't work "Unhandled exception type IOException". – Suhail Sullad Feb 06 '17 at 04:32
  • @SuhailSullad What part of the code does the compiler error point to? To my knowledge, I didn't add any code that throws that exception, so the problem would be in your original code also. – 4castle Feb 06 '17 at 05:01
  • Original code had the`IOException` handled. when i try to compile the above code Eclipse errors out saying `ClassPath.from(ClassLoader.getSystemClassLoader())` has unhandled exception. – Suhail Sullad Feb 07 '17 at 04:47
  • I don't see where it's handled in your original code. If you need help solving that error, look at [this question](http://stackoverflow.com/q/2305966/5743988). I've given you the answer otherwise. – 4castle Feb 07 '17 at 06:09
  • weird eclipse IDE behavior. Anyway figured out what was causing the issue and resolved it. Thanks. – Suhail Sullad Feb 07 '17 at 13:20