/* package whatever; // don't place package name! */

import java.util.*;
import java.lang.*;
import java.io.*;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.lang.reflect.ParameterizedType;
import java.util.Arrays;
import java.util.stream.*;

class ToBeReflectedOn {
	public static ArrayList<String> returnsAStringList() {
		return new ArrayList<String>();	
	}
}

class Ideone
{
	public static void main (String[] args) throws java.lang.Exception
	{
		ToBeReflectedOn toBeReflectedOn = new ToBeReflectedOn();
		Class c = toBeReflectedOn.getClass();
        Method returnsAStringListMethod = Arrays.stream(c.getDeclaredMethods())
        .filter(m -> m.getName() == "returnsAStringList")
        .collect(Collectors.toList()).get(0);
         System.out.println(
        	"\nName: " + returnsAStringListMethod.getName()
        	+ "\nDeclaring Class: " + returnsAStringListMethod.getDeclaringClass().getName()
        	+ "\nReturn Type: " + returnsAStringListMethod.getReturnType().getName()
        	+ "\nGeneric Return Type: " + returnsAStringListMethod.getGenericReturnType().getTypeName()
        	+ "\nStackOverflow suggested answer: " + simpleTypeName(returnsAStringListMethod.getGenericReturnType())
        );
	}
	
	static String simpleTypeName(Type t) {
    if (t instanceof ParameterizedType) {
      ParameterizedType p = (ParameterizedType) t;
      return simpleTypeName(p.getRawType())
          + Stream.of(p.getActualTypeArguments())
              // Recurse to handle the type arguments.
              .map(Ideone::simpleTypeName)
              .collect(Collectors.joining(", ", "<", ">"));
    } else if (t instanceof Class) {
      Class<?> c = (Class<?>) t;
      return c.getSimpleName();
    } else {
    	return t.getTypeName();
      // ... handle other Type subtypes.
    }
  }
}