package com.github.ompc.greys.core.textui.ext;
import com.github.ompc.greys.core.GlobalOptions;
import com.github.ompc.greys.core.textui.TComponent;
import com.github.ompc.greys.core.util.SimpleDateFormatHolder;
import com.google.gson.Gson;
import java.io.PrintWriter;
import java.io.StringReader;
import java.io.StringWriter;
import java.lang.reflect.Field;
import java.util.*;
import static com.github.ompc.greys.core.util.GaStringUtils.newString;
import static java.lang.String.format;
/**
* 对象控件<br/>
* 能展示出一个对象的内部结构
* Created by oldmanpushcart@gmail.com on 15/5/20.
*/
public class TObject implements TComponent {
private final Object object;
private final Integer expend;
public TObject(Object object, Integer expend) {
this.object = object;
this.expend = expend;
}
private boolean isNeedExpend() {
return null != expend
&& expend >= 0;
}
@Override
public String rendering() {
try {
if (isNeedExpend()) {
if (GlobalOptions.isUsingJson) {
return new Gson().toJson(object);
}
return toString(object, 0, expend);
} else {
return newString(object);
}
} catch(Throwable t) {
return "ERROR DATA!!!";
}
}
private final static String TAB = " ";
private final static Map<Byte, String> ASCII_MAP = new HashMap<Byte, String>();
static {
ASCII_MAP.put((byte) 0, "NUL");
ASCII_MAP.put((byte) 1, "SOH");
ASCII_MAP.put((byte) 2, "STX");
ASCII_MAP.put((byte) 3, "ETX");
ASCII_MAP.put((byte) 4, "EOT");
ASCII_MAP.put((byte) 5, "ENQ");
ASCII_MAP.put((byte) 6, "ACK");
ASCII_MAP.put((byte) 7, "BEL");
ASCII_MAP.put((byte) 8, "BS");
ASCII_MAP.put((byte) 9, "HT");
ASCII_MAP.put((byte) 10, "LF");
ASCII_MAP.put((byte) 11, "VT");
ASCII_MAP.put((byte) 12, "FF");
ASCII_MAP.put((byte) 13, "CR");
ASCII_MAP.put((byte) 14, "SO");
ASCII_MAP.put((byte) 15, "SI");
ASCII_MAP.put((byte) 16, "DLE");
ASCII_MAP.put((byte) 17, "DC1");
ASCII_MAP.put((byte) 18, "DC2");
ASCII_MAP.put((byte) 19, "DC3");
ASCII_MAP.put((byte) 20, "DC4");
ASCII_MAP.put((byte) 21, "NAK");
ASCII_MAP.put((byte) 22, "SYN");
ASCII_MAP.put((byte) 23, "ETB");
ASCII_MAP.put((byte) 24, "CAN");
ASCII_MAP.put((byte) 25, "EM");
ASCII_MAP.put((byte) 26, "SUB");
ASCII_MAP.put((byte) 27, "ESC");
ASCII_MAP.put((byte) 28, "FS");
ASCII_MAP.put((byte) 29, "GS");
ASCII_MAP.put((byte) 30, "RS");
ASCII_MAP.put((byte) 31, "US");
ASCII_MAP.put((byte) 127, "DEL");
}
private static String toString(Object obj, int deep, int expand) {
final StringBuilder buf = new StringBuilder();
if (null == obj) {
buf.append("null");
} else {
final Class<?> clazz = obj.getClass();
final String className = clazz.getSimpleName();
// 7种基础类型,直接输出@类型[值]
if (Integer.class.isInstance(obj)
|| Long.class.isInstance(obj)
|| Float.class.isInstance(obj)
|| Double.class.isInstance(obj)
// || Character.class.isInstance(obj)
|| Short.class.isInstance(obj)
|| Byte.class.isInstance(obj)
|| Boolean.class.isInstance(obj)) {
buf.append(format("@%s[%s]", className, obj));
}
// Char要特殊处理,因为有不可见字符的因素
else if (Character.class.isInstance(obj)) {
final Character c = (Character) obj;
// ASCII的可见字符
if (c >= 32
&& c <= 126) {
buf.append(format("@%s[%s]", className, c));
}
// ASCII的控制字符
else if (ASCII_MAP.containsKey((byte) c.charValue())) {
buf.append(format("@%s[%s]", className, ASCII_MAP.get((byte) c.charValue())));
}
// 超过ASCII的编码范围
else {
buf.append(format("@%s[%s]", className, c));
}
}
// 字符串类型单独处理
else if (String.class.isInstance(obj)) {
final StringBuilder bufOfString = new StringBuilder();
for (Character c : ((String) obj).toCharArray()) {
switch (c) {
case '\n':
bufOfString.append("\\n");
break;
case '\r':
bufOfString.append("\\r");
break;
default:
bufOfString.append(c);
}//switch
}//for
buf.append(format("@%s[%s]", className, bufOfString));
}
// 集合类输出
else if (Collection.class.isInstance(obj)) {
@SuppressWarnings("unchecked") final Collection<Object> collection = (Collection<Object>) obj;
// 非根节点或空集合只展示摘要信息
if (!isExpand(deep, expand)
|| collection.isEmpty()) {
buf.append(format("@%s[isTop=%s;size=%d]",
className,
collection.isEmpty(),
collection.size()));
}
// 展开展示
else {
final StringBuilder bufOfCollection = new StringBuilder();
bufOfCollection.append(format("@%s[", className));
for (Object e : collection) {
bufOfCollection.append("\n").append(toString(e, deep + 1, expand)).append(",\n");
}
bufOfCollection.append("]");
buf.append(bufOfCollection);
}
}
// Map类输出
else if (Map.class.isInstance(obj)) {
@SuppressWarnings("unchecked") final Map<Object, Object> map = (Map<Object, Object>) obj;
// 非根节点或空集合只展示摘要信息
if (!isExpand(deep, expand)
|| map.isEmpty()) {
buf.append(format("@%s[isTop=%s;size=%d]",
className,
map.isEmpty(),
map.size()));
} else {
final StringBuilder bufOfMap = new StringBuilder();
bufOfMap.append(format("@%s[", className));
for (Map.Entry<Object, Object> entry : map.entrySet()) {
bufOfMap.append("\n").append(toString(entry.getKey(), deep + 1, expand))
.append(":")
.append(toString(entry.getValue(), deep + 1, expand).trim())
.append(",\n");
}
bufOfMap.append("]");
buf.append(bufOfMap);
}
}
// 数组类输出
else if (obj.getClass().isArray()) {
final String typeName = obj.getClass().getSimpleName();
// int[]
if (typeName.equals("int[]")) {
final int[] arrays = (int[]) obj;
// 非根节点或空集合只展示摘要信息
if (!isExpand(deep, expand)
|| arrays.length == 0) {
buf.append(format("@%s[isTop=%s;size=%d]",
typeName,
arrays.length == 0,
arrays.length));
}
// 展开展示
else {
final StringBuilder bufOfArray = new StringBuilder();
bufOfArray.append(format("@%s[", className));
for (Object e : arrays) {
bufOfArray.append("\n").append(toString(e, deep + 1, expand)).append(",");
}
bufOfArray.append("\n]");
buf.append(bufOfArray);
}
}
// long[]
else if (typeName.equals("long[]")) {
final long[] arrays = (long[]) obj;
// 非根节点或空集合只展示摘要信息
if (!isExpand(deep, expand)
|| arrays.length == 0) {
buf.append(format("@%s[isTop=%s;size=%d]",
typeName,
arrays.length == 0,
arrays.length));
}
// 展开展示
else {
final StringBuilder bufOfArray = new StringBuilder();
bufOfArray.append(format("@%s[", className));
for (Object e : arrays) {
bufOfArray.append("\n").append(toString(e, deep + 1, expand)).append(",");
}
bufOfArray.append("\n]");
buf.append(bufOfArray);
}
}
// short[]
else if (typeName.equals("short[]")) {
final short[] arrays = (short[]) obj;
// 非根节点或空集合只展示摘要信息
if (!isExpand(deep, expand)
|| arrays.length == 0) {
buf.append(format("@%s[isTop=%s;size=%d]",
typeName,
arrays.length == 0,
arrays.length));
}
// 展开展示
else {
final StringBuilder bufOfArray = new StringBuilder();
bufOfArray.append(format("@%s[", className));
for (Object e : arrays) {
bufOfArray.append("\n").append(toString(e, deep + 1, expand)).append(",");
}
bufOfArray.append("\n]");
buf.append(bufOfArray);
}
}
// float[]
else if (typeName.equals("float[]")) {
final float[] arrays = (float[]) obj;
// 非根节点或空集合只展示摘要信息
if (!isExpand(deep, expand)
|| arrays.length == 0) {
buf.append(format("@%s[isTop=%s;size=%d]",
typeName,
arrays.length == 0,
arrays.length));
}
// 展开展示
else {
final StringBuilder bufOfArray = new StringBuilder();
bufOfArray.append(format("@%s[", className));
for (Object e : arrays) {
bufOfArray.append("\n").append(toString(e, deep + 1, expand)).append(",");
}
bufOfArray.append("\n]");
buf.append(bufOfArray);
}
}
// double[]
else if (typeName.equals("double[]")) {
final double[] arrays = (double[]) obj;
// 非根节点或空集合只展示摘要信息
if (!isExpand(deep, expand)
|| arrays.length == 0) {
buf.append(format("@%s[isTop=%s;size=%d]",
typeName,
arrays.length == 0,
arrays.length));
}
// 展开展示
else {
final StringBuilder bufOfArray = new StringBuilder();
bufOfArray.append(format("@%s[", className));
for (Object e : arrays) {
bufOfArray.append("\n").append(toString(e, deep + 1, expand)).append(",");
}
bufOfArray.append("\n]");
buf.append(bufOfArray);
}
}
// boolean[]
else if (typeName.equals("boolean[]")) {
final boolean[] arrays = (boolean[]) obj;
// 非根节点或空集合只展示摘要信息
if (!isExpand(deep, expand)
|| arrays.length == 0) {
buf.append(format("@%s[isTop=%s;size=%d]",
typeName,
arrays.length == 0,
arrays.length));
}
// 展开展示
else {
final StringBuilder bufOfArray = new StringBuilder();
bufOfArray.append(format("@%s[", className));
for (Object e : arrays) {
bufOfArray.append("\n").append(toString(e, deep + 1, expand)).append(",");
}
bufOfArray.append("\n]");
buf.append(bufOfArray);
}
}
// char[]
else if (typeName.equals("char[]")) {
final char[] arrays = (char[]) obj;
// 非根节点或空集合只展示摘要信息
if (!isExpand(deep, expand)
|| arrays.length == 0) {
buf.append(format("@%s[isTop=%s;size=%d]",
typeName,
arrays.length == 0,
arrays.length));
}
// 展开展示
else {
final StringBuilder bufOfArray = new StringBuilder();
bufOfArray.append(format("@%s[", className));
for (Object e : arrays) {
bufOfArray.append("\n").append(toString(e, deep + 1, expand)).append(",");
}
bufOfArray.append("\n]");
buf.append(bufOfArray);
}
}
// byte[]
else if (typeName.equals("byte[]")) {
final byte[] arrays = (byte[]) obj;
// 非根节点或空集合只展示摘要信息
if (!isExpand(deep, expand)
|| arrays.length == 0) {
buf.append(format("@%s[isTop=%s;size=%d]",
typeName,
arrays.length == 0,
arrays.length));
}
// 展开展示
else {
final StringBuilder bufOfArray = new StringBuilder();
bufOfArray.append(format("@%s[", className));
for (Object e : arrays) {
bufOfArray.append("\n").append(toString(e, deep + 1, expand)).append(",");
}
bufOfArray.append("\n]");
buf.append(bufOfArray);
}
}
// Object[]
else {
final Object[] arrays = (Object[]) obj;
// 非根节点或空集合只展示摘要信息
if (!isExpand(deep, expand)
|| arrays.length == 0) {
buf.append(format("@%s[isTop=%s;size=%d]",
typeName,
arrays.length == 0,
arrays.length));
}
// 展开展示
else {
final StringBuilder bufOfArray = new StringBuilder();
bufOfArray.append(format("@%s[", className));
for (Object e : arrays) {
bufOfArray.append("\n").append(toString(e, deep + 1, expand)).append(",");
}
bufOfArray.append("\n]");
buf.append(bufOfArray);
}
}
}
// Throwable输出
else if (Throwable.class.isInstance(obj)) {
if (!isExpand(deep, expand)) {
buf.append(format("@%s[%s]", className, obj));
} else {
final Throwable throwable = (Throwable) obj;
final StringWriter sw = new StringWriter();
final PrintWriter pw = new PrintWriter(sw);
throwable.printStackTrace(pw);
// buf.append(format("@%s[\n",className));
buf.append(sw.toString());
// buf.append("]");
}
}
// Date输出
else if (Date.class.isInstance(obj)) {
buf.append(format("@%s[%s]", className, SimpleDateFormatHolder.getInstance().format((Date) obj)));
}
// 普通Object输出
else {
if (!isExpand(deep, expand)) {
buf.append(format("@%s[%s]", className, obj));
} else {
final StringBuilder bufOfObject = new StringBuilder();
bufOfObject.append(format("@%s[", className));
final Field[] fields = obj.getClass().getDeclaredFields();
if (null != fields) {
for (Field field : fields) {
if (!field.isAccessible()) {
field.setAccessible(true);
}
try {
final Object value = field.get(obj);
bufOfObject.append("\n").append(TAB).append(field.getName())
.append("=")
.append(toString(value, deep + 1, expand).trim())
.append(",");
} catch (Throwable t) {
//
}
}//for
bufOfObject.append("\n");
}//if
bufOfObject.append("]");
buf.append(bufOfObject);
}
}
}
// TAB偏移
final StringBuilder tabBuf = new StringBuilder();
Scanner scanner = null;
try {
scanner = new Scanner(new StringReader(buf.toString()));
while (scanner.hasNextLine()) {
final String line = scanner.nextLine();
if (!isRoot(deep)) {
tabBuf.append(TAB);
}
tabBuf.append(line).append("\n");
}
} finally {
if (null != scanner) {
scanner.close();
}
}
if (tabBuf.length() > 0) {
tabBuf.deleteCharAt(tabBuf.length() - 1);
}
return tabBuf.toString();
}
/**
* 是否根节点
*
* @param deep 深度
* @return true:根节点 / false:非根节点
*/
private static boolean isRoot(int deep) {
return deep == 0;
}
/**
* 是否展开当前深度的节点
*
* @param deep 当前节点的深度
* @param expand 展开极限
* @return true:当前节点需要展开 / false:当前节点不需要展开
*/
private static boolean isExpand(int deep, int expand) {
return deep < expand;
}
}