Skip to content

Instantly share code, notes, and snippets.

@ipid
Last active April 3, 2020 10:47
Show Gist options
  • Save ipid/3568e213bdd7ec7ea8308e8af632755c to your computer and use it in GitHub Desktop.
Save ipid/3568e213bdd7ec7ea8308e8af632755c to your computer and use it in GitHub Desktop.
Print class methods and fields info through reflection, as if you were reading source code.
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.*;
import java.util.stream.Collectors;
/**
* Usage:
* <code>
* System.out.print(printInfo(java.time.format.DateTimeFormatter.class));
* </code>
*
* It will print things like:
* <code>
* package java.time.format;
*
* import java.text.Format;
* import java.time.Period;
* import java.time.ZoneId;
* // ...
*
* class DateTimeFormatter {
*
* private CompositePrinterParser printerParser;
* private Locale locale;
* // ...
* public static DateTimeFormatter ISO_LOCAL_DATE;
* public static DateTimeFormatter ISO_OFFSET_DATE;
* public static DateTimeFormatter ISO_DATE;
* // ...
*
* public String toString () {}
* public String format () {}
* public TemporalAccessor parse () {}
* public Object parse () {}
* public TemporalAccessor parse () {}
* public static DateTimeFormatter ofPattern () {}
* public static DateTimeFormatter ofPattern () {}
* public static TemporalQuery parsedLeapSecond () {}
* public Locale getLocale () {}
* public DateTimeFormatter withLocale () {}
* public Set getResolverFields () {}
* public DateTimeFormatter withResolverFields () {}
* private TemporalAccessor parseResolved0 () {}
* public TemporalAccessor parseUnresolved () {}
* private DateTimeParseContext parseUnresolved0 () {}
* CompositePrinterParser toPrinterParser () {}
* public Format toFormat () {}
* public Format toFormat () {}
* private static Boolean lambda$static$1 () {}
* private static Period lambda$static$0 () {}
* // ...
*
* }
* </code>
*/
public class PrintClassInfo {
public static void main(String[] args) {
System.out.print(printInfo(java.time.format.DateTimeFormatter.class));
}
public static String printInfo(Class<?> cls) {
List<String> result = new ArrayList<>();
// --- collect info ---
Set<String> imports = new HashSet<>();
String packageName = cls.getPackageName();
String classTitle;
{
String classType, upperName;
if (cls.isInterface()) {
classType = "interface";
} else {
classType = "class";
}
Class<?> upper = cls.getSuperclass();
if (upper == null || isTheObject(upper)) {
upperName = "";
} else if (isTheEnum(upper)) {
classType = "enum";
upperName = "";
} else {
upperName = upper.getSimpleName();
addImportIfNotInSamePackage(cls, upper, imports);
}
classTitle = classType + " "
+ cls.getSimpleName() + " "
+ (upperName.equals("") ? "" : "extends " + upperName + " ")
+ "{\n";
}
List<String> fields = new ArrayList<>();
for (Field field : cls.getDeclaredFields()) {
List<String> builder = new ArrayList<>();
String typeDescribe = getTypeDescribe(field.getModifiers());
if (!typeDescribe.equals("")) {
builder.add(typeDescribe);
}
addImportIfNotInSamePackage(cls, field.getType(), imports);
builder.add(field.getType().getSimpleName());
builder.add(field.getName());
fields.add(" " + String.join(" ", builder) + ";\n");
}
List<String> methods = new ArrayList<>();
for (Method method : cls.getDeclaredMethods()) {
List<String> builder = new ArrayList<>();
String typeDescribe = getTypeDescribe(method.getModifiers());
if (!typeDescribe.equals("")) {
builder.add(typeDescribe);
}
addImportIfNotInSamePackage(cls, method.getReturnType(), imports);
builder.add(method.getReturnType().getSimpleName());
builder.add(method.getName());
builder.add("()");
builder.add("{}");
methods.add(" " + String.join(" ", builder) + "\n");
}
// --- output ---
List<String> importList = new ArrayList<>(imports);
Collections.sort(importList);
if (!packageName.equals("")) {
result.add("package " + packageName + ";\n");
}
result.add(importList.stream().map(x -> "import " + x + ";\n").collect(Collectors.joining("")));
result.add(classTitle);
result.add(String.join("", fields));
result.add(String.join("", methods));
result.add("}");
return String.join("\n", result);
}
private static boolean isTheObject(Class<?> cls) {
return cls.getCanonicalName().equals("java.lang.Object");
}
private static boolean isTheEnum(Class<?> cls) {
return cls.getCanonicalName().equals("java.lang.Enum");
}
private static void addImportIfNotInSamePackage(Class<?> curr, Class<?> other, Set<? super String> set) {
if (other.getPackageName().equals("") || other.getPackageName().equals("java.lang")) {
return;
}
if (!curr.getPackageName().equals(other.getPackageName())) {
set.add(other.getPackageName() + "." + other.getSimpleName());
}
}
private static String getTypeDescribe(int modifier) {
List<String> builder = new ArrayList<>();
if (Modifier.isPublic(modifier)) {
builder.add("public");
}
if (Modifier.isPrivate(modifier)) {
builder.add("private");
}
if (Modifier.isStatic(modifier)) {
builder.add("static");
}
return String.join(" ", builder);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment