From 2e45264fb89f009f7e31c9b36f6e39c1de5fb471 Mon Sep 17 00:00:00 2001 From: gongdewei Date: Mon, 26 Jul 2021 18:29:00 +0800 Subject: [PATCH] change the type of ObjectVO to fully-qualified class name --- .../core/util/object/ObjectInspector.java | 20 +- .../core/util/object/ObjectRenderer.java | 8 +- .../arthas/core/model/ObjectRenderTest.java | 213 ++++++++++++++---- 3 files changed, 190 insertions(+), 51 deletions(-) diff --git a/core/src/main/java/com/taobao/arthas/core/util/object/ObjectInspector.java b/core/src/main/java/com/taobao/arthas/core/util/object/ObjectInspector.java index 04be9efc6..c20897d64 100644 --- a/core/src/main/java/com/taobao/arthas/core/util/object/ObjectInspector.java +++ b/core/src/main/java/com/taobao/arthas/core/util/object/ObjectInspector.java @@ -48,7 +48,7 @@ public class ObjectInspector { return objectVO; } catch (ObjectTooLargeException e) { // unreachable statement - return new ObjectVO(object != null ? object.getClass().getSimpleName() : "", e.getMessage()); + return new ObjectVO(object != null ? getTypeName(object.getClass()) : "", e.getMessage()); } } @@ -73,7 +73,7 @@ public class ObjectInspector { } else { final Class clazz = obj.getClass(); - final String className = clazz.getSimpleName(); + final String className = getTypeName(clazz); // 7种基础类型,直接输出@类型[值] if (Integer.class.isInstance(obj) @@ -136,7 +136,7 @@ public class ObjectInspector { } } catch (ObjectTooLargeException ex) { //ignore - list.add(new ObjectVO(el != null ? el.getClass().getSimpleName() : "", "...")); + list.add(new ObjectVO(el != null ? getTypeName(el.getClass()) : "", "...")); break; } } @@ -172,10 +172,10 @@ public class ObjectInspector { } catch (ObjectTooLargeException e) { //ignore error if (keyObj == null) { - keyObj = new ObjectVO(entry.getKey() != null ? entry.getKey().getClass().getSimpleName() : "", "..."); + keyObj = new ObjectVO(entry.getKey() != null ? getTypeName(entry.getKey().getClass()) : "", "..."); } if (valueObj == null) { - valueObj = new ObjectVO(entry.getValue() != null ? entry.getValue().getClass().getSimpleName() : "", "..."); + valueObj = new ObjectVO(entry.getValue() != null ? getTypeName(entry.getValue().getClass()) : "", "..."); } list.add(ObjectVO.ofKeyValue(keyObj, valueObj)); break; @@ -189,7 +189,7 @@ public class ObjectInspector { // 数组类输出 else if (obj.getClass().isArray()) { - final String typeName = obj.getClass().getSimpleName(); + final String typeName = getTypeName(obj.getClass()); // int[] if (typeName.equals("int[]")) { @@ -480,7 +480,7 @@ public class ObjectInspector { elements[i] = inspectObject(arrays[i], deep+1, expand); } catch (ObjectTooLargeException ex) { //ignore error - elements[i] = new ObjectVO(arrays[i] != null ? arrays[i].getClass().getSimpleName() : "", "..."); + elements[i] = new ObjectVO(arrays[i] != null ? getTypeName(arrays[i].getClass()) : "", "..."); break; } } @@ -553,7 +553,7 @@ public class ObjectInspector { fieldVOList.add(fieldObjectVO); } catch (ObjectTooLargeException t) { - fieldVOList.add(new ObjectVO(field.getName(), field.getType().getSimpleName(), "...")); + fieldVOList.add(new ObjectVO(field.getName(), getTypeName(field.getType()), "...")); break; } catch (Throwable t) { // ignore @@ -571,6 +571,10 @@ public class ObjectInspector { } } + protected String getTypeName(Class objClass) { + return objClass.isArray() ? objClass.getSimpleName() : objClass.getName(); + } + private void checkObjectAmount() throws ObjectTooLargeException { if (objectCount >= objectNumberLimit){ throw new ObjectTooLargeException("Number of objects exceeds limit: "+ objectNumberLimit); diff --git a/core/src/main/java/com/taobao/arthas/core/util/object/ObjectRenderer.java b/core/src/main/java/com/taobao/arthas/core/util/object/ObjectRenderer.java index 04fc12839..92d895688 100644 --- a/core/src/main/java/com/taobao/arthas/core/util/object/ObjectRenderer.java +++ b/core/src/main/java/com/taobao/arthas/core/util/object/ObjectRenderer.java @@ -41,7 +41,8 @@ public abstract class ObjectRenderer { if (vo.getType() != null) { //object type - sb.append('@').append(vo.getType()).append('['); + String type = toSimpleType(vo.getType()); + sb.append('@').append(type).append('['); } // object value start @@ -74,6 +75,11 @@ public abstract class ObjectRenderer { } } + private static String toSimpleType(String typeName) { + int p = typeName.lastIndexOf('.'); // trim package name + return p >= 0 ? typeName.substring(p+1) : typeName; + } + private static void renderComplexObject(ObjectVO vo, int deep, StringBuffer sb) { sb.append('\n'); for (ObjectVO field : vo.getFields()) { diff --git a/core/src/test/java/com/taobao/arthas/core/model/ObjectRenderTest.java b/core/src/test/java/com/taobao/arthas/core/model/ObjectRenderTest.java index 317b097c6..3c5cbcb45 100644 --- a/core/src/test/java/com/taobao/arthas/core/model/ObjectRenderTest.java +++ b/core/src/test/java/com/taobao/arthas/core/model/ObjectRenderTest.java @@ -5,6 +5,7 @@ import com.taobao.arthas.core.command.model.ObjectVO; import com.taobao.arthas.core.util.object.ObjectInspector; import com.taobao.arthas.core.util.object.ObjectRenderer; import org.assertj.core.api.Assertions; +import org.hamcrest.core.StringContains; import org.junit.Assert; import org.junit.Test; @@ -182,7 +183,7 @@ public class ObjectRenderTest { "]"); testSimpleArray(new Object[]{1.0, 2L, 3.0f}, - "{\"size\":3,\"type\":\"Object[]\",\"value\":[{\"type\":\"Double\",\"value\":1.0},{\"type\":\"Long\",\"value\":2},{\"type\":\"Float\",\"value\":3.0}]}", + "{\"size\":3,\"type\":\"Object[]\",\"value\":[{\"type\":\"java.lang.Double\",\"value\":1.0},{\"type\":\"java.lang.Long\",\"value\":2},{\"type\":\"java.lang.Float\",\"value\":3.0}]}", "@Object[][\n" + " @Double[1.0],\n" + " @Long[2],\n" + @@ -190,7 +191,7 @@ public class ObjectRenderTest { "]"); testSimpleArray(new String[]{"str1", "2", "3"}, - "{\"size\":3,\"type\":\"String[]\",\"value\":[{\"type\":\"String\",\"value\":\"str1\"},{\"type\":\"String\",\"value\":\"2\"},{\"type\":\"String\",\"value\":\"3\"}]}", + "{\"size\":3,\"type\":\"String[]\",\"value\":[{\"type\":\"java.lang.String\",\"value\":\"str1\"},{\"type\":\"java.lang.String\",\"value\":\"2\"},{\"type\":\"java.lang.String\",\"value\":\"3\"}]}", "@String[][\n" + " @String[str1],\n" + " @String[2],\n" + @@ -248,7 +249,7 @@ public class ObjectRenderTest { " @String[boolValue] : @Boolean[true],\n" + " @String[doubleValue] : @Double[123.0],\n" + " @String[floatValue] : @Float[123.0],\n" + - " @String[listValue] : @ArrayList[isEmpty=false;size=3],\n" + + " @String[listValue] : @Arrays$ArrayList[isEmpty=false;size=3],\n" + " @String[IntArray] : @Integer[][isEmpty=false;size=3],\n" + " @String[objectArray] : @Object[][isEmpty=false;size=3],\n" + " @String[objectValue] : @Object[java.lang.Object@ffffffff],\n" + @@ -264,7 +265,7 @@ public class ObjectRenderTest { " @String[boolValue] : @Boolean[true],\n" + " @String[doubleValue] : @Double[123.0],\n" + " @String[floatValue] : @Float[123.0],\n" + - " @String[listValue] : @ArrayList[\n" + + " @String[listValue] : @Arrays$ArrayList[\n" + " @Integer[1],\n" + " @Integer[2],\n" + " @Integer[3],\n" + @@ -286,7 +287,7 @@ public class ObjectRenderTest { } private void printObject(ObjectVO objectVO) { - System.out.println(JSON.toJSONString(objectVO)); + System.out.println(JSON.toJSONString(objectVO, true)); System.out.println(); System.out.println(ObjectRenderer.render(objectVO)); System.out.println(); @@ -325,35 +326,155 @@ public class ObjectRenderTest { ObjectVO objectVO = inspectObject(nestedClass, 3); printObject(objectVO); - Assert.assertEquals("@NestedClass[\n" + + // object view + Assert.assertEquals("@ObjectRenderTest$NestedClass[\n" + " code=@Integer[100],\n" + - " c1=@NestedClass[\n" + + " c1=@ObjectRenderTest$NestedClass[\n" + " code=@Integer[1],\n" + - " c1=@NestedClass[\n" + + " c1=@ObjectRenderTest$NestedClass[\n" + " code=@Integer[1],\n" + - " c1=@NestedClass[com.taobao.arthas.core.model.ObjectRenderTest$NestedClass@ffffffff],\n" + - " c2=@NestedClass[com.taobao.arthas.core.model.ObjectRenderTest$NestedClass@ffffffff],\n" + + " c1=@ObjectRenderTest$NestedClass[com.taobao.arthas.core.model.ObjectRenderTest$NestedClass@ffffffff],\n" + + " c2=@ObjectRenderTest$NestedClass[com.taobao.arthas.core.model.ObjectRenderTest$NestedClass@ffffffff],\n" + " ],\n" + - " c2=@NestedClass[\n" + + " c2=@ObjectRenderTest$NestedClass[\n" + " code=@Integer[2],\n" + - " c1=@NestedClass[com.taobao.arthas.core.model.ObjectRenderTest$NestedClass@ffffffff],\n" + - " c2=@NestedClass[com.taobao.arthas.core.model.ObjectRenderTest$NestedClass@ffffffff],\n" + + " c1=@ObjectRenderTest$NestedClass[com.taobao.arthas.core.model.ObjectRenderTest$NestedClass@ffffffff],\n" + + " c2=@ObjectRenderTest$NestedClass[com.taobao.arthas.core.model.ObjectRenderTest$NestedClass@ffffffff],\n" + " ],\n" + " ],\n" + - " c2=@NestedClass[\n" + + " c2=@ObjectRenderTest$NestedClass[\n" + " code=@Integer[2],\n" + - " c1=@NestedClass[\n" + + " c1=@ObjectRenderTest$NestedClass[\n" + " code=@Integer[1],\n" + - " c1=@NestedClass[com.taobao.arthas.core.model.ObjectRenderTest$NestedClass@ffffffff],\n" + - " c2=@NestedClass[com.taobao.arthas.core.model.ObjectRenderTest$NestedClass@ffffffff],\n" + + " c1=@ObjectRenderTest$NestedClass[com.taobao.arthas.core.model.ObjectRenderTest$NestedClass@ffffffff],\n" + + " c2=@ObjectRenderTest$NestedClass[com.taobao.arthas.core.model.ObjectRenderTest$NestedClass@ffffffff],\n" + " ],\n" + - " c2=@NestedClass[\n" + + " c2=@ObjectRenderTest$NestedClass[\n" + " code=@Integer[2],\n" + - " c1=@NestedClass[com.taobao.arthas.core.model.ObjectRenderTest$NestedClass@ffffffff],\n" + - " c2=@NestedClass[com.taobao.arthas.core.model.ObjectRenderTest$NestedClass@ffffffff],\n" + + " c1=@ObjectRenderTest$NestedClass[com.taobao.arthas.core.model.ObjectRenderTest$NestedClass@ffffffff],\n" + + " c2=@ObjectRenderTest$NestedClass[com.taobao.arthas.core.model.ObjectRenderTest$NestedClass@ffffffff],\n" + " ],\n" + " ],\n" + "]", replaceHashCode(ObjectRenderer.render(objectVO))); + + // json + Assert.assertEquals("{\n" + + " \"fields\":[\n" + + " {\n" + + " \"name\":\"code\",\n" + + " \"type\":\"java.lang.Integer\",\n" + + " \"value\":100\n" + + " },\n" + + " {\n" + + " \"fields\":[\n" + + " {\n" + + " \"name\":\"code\",\n" + + " \"type\":\"java.lang.Integer\",\n" + + " \"value\":1\n" + + " },\n" + + " {\n" + + " \"fields\":[\n" + + " {\n" + + " \"name\":\"code\",\n" + + " \"type\":\"java.lang.Integer\",\n" + + " \"value\":1\n" + + " },\n" + + " {\n" + + " \"name\":\"c1\",\n" + + " \"type\":\"com.taobao.arthas.core.model.ObjectRenderTest$NestedClass\",\n" + + " \"value\":\"com.taobao.arthas.core.model.ObjectRenderTest$NestedClass@ffffffff\"\n" + + " },\n" + + " {\n" + + " \"name\":\"c2\",\n" + + " \"type\":\"com.taobao.arthas.core.model.ObjectRenderTest$NestedClass\",\n" + + " \"value\":\"com.taobao.arthas.core.model.ObjectRenderTest$NestedClass@ffffffff\"\n" + + " }\n" + + " ],\n" + + " \"name\":\"c1\",\n" + + " \"type\":\"com.taobao.arthas.core.model.ObjectRenderTest$NestedClass\"\n" + + " },\n" + + " {\n" + + " \"fields\":[\n" + + " {\n" + + " \"name\":\"code\",\n" + + " \"type\":\"java.lang.Integer\",\n" + + " \"value\":2\n" + + " },\n" + + " {\n" + + " \"name\":\"c1\",\n" + + " \"type\":\"com.taobao.arthas.core.model.ObjectRenderTest$NestedClass\",\n" + + " \"value\":\"com.taobao.arthas.core.model.ObjectRenderTest$NestedClass@ffffffff\"\n" + + " },\n" + + " {\n" + + " \"name\":\"c2\",\n" + + " \"type\":\"com.taobao.arthas.core.model.ObjectRenderTest$NestedClass\",\n" + + " \"value\":\"com.taobao.arthas.core.model.ObjectRenderTest$NestedClass@ffffffff\"\n" + + " }\n" + + " ],\n" + + " \"name\":\"c2\",\n" + + " \"type\":\"com.taobao.arthas.core.model.ObjectRenderTest$NestedClass\"\n" + + " }\n" + + " ],\n" + + " \"name\":\"c1\",\n" + + " \"type\":\"com.taobao.arthas.core.model.ObjectRenderTest$NestedClass\"\n" + + " },\n" + + " {\n" + + " \"fields\":[\n" + + " {\n" + + " \"name\":\"code\",\n" + + " \"type\":\"java.lang.Integer\",\n" + + " \"value\":2\n" + + " },\n" + + " {\n" + + " \"fields\":[\n" + + " {\n" + + " \"name\":\"code\",\n" + + " \"type\":\"java.lang.Integer\",\n" + + " \"value\":1\n" + + " },\n" + + " {\n" + + " \"name\":\"c1\",\n" + + " \"type\":\"com.taobao.arthas.core.model.ObjectRenderTest$NestedClass\",\n" + + " \"value\":\"com.taobao.arthas.core.model.ObjectRenderTest$NestedClass@ffffffff\"\n" + + " },\n" + + " {\n" + + " \"name\":\"c2\",\n" + + " \"type\":\"com.taobao.arthas.core.model.ObjectRenderTest$NestedClass\",\n" + + " \"value\":\"com.taobao.arthas.core.model.ObjectRenderTest$NestedClass@ffffffff\"\n" + + " }\n" + + " ],\n" + + " \"name\":\"c1\",\n" + + " \"type\":\"com.taobao.arthas.core.model.ObjectRenderTest$NestedClass\"\n" + + " },\n" + + " {\n" + + " \"fields\":[\n" + + " {\n" + + " \"name\":\"code\",\n" + + " \"type\":\"java.lang.Integer\",\n" + + " \"value\":2\n" + + " },\n" + + " {\n" + + " \"name\":\"c1\",\n" + + " \"type\":\"com.taobao.arthas.core.model.ObjectRenderTest$NestedClass\",\n" + + " \"value\":\"com.taobao.arthas.core.model.ObjectRenderTest$NestedClass@ffffffff\"\n" + + " },\n" + + " {\n" + + " \"name\":\"c2\",\n" + + " \"type\":\"com.taobao.arthas.core.model.ObjectRenderTest$NestedClass\",\n" + + " \"value\":\"com.taobao.arthas.core.model.ObjectRenderTest$NestedClass@ffffffff\"\n" + + " }\n" + + " ],\n" + + " \"name\":\"c2\",\n" + + " \"type\":\"com.taobao.arthas.core.model.ObjectRenderTest$NestedClass\"\n" + + " }\n" + + " ],\n" + + " \"name\":\"c2\",\n" + + " \"type\":\"com.taobao.arthas.core.model.ObjectRenderTest$NestedClass\"\n" + + " }\n" + + " ],\n" + + " \"type\":\"com.taobao.arthas.core.model.ObjectRenderTest$NestedClass\"\n" + + "}", + replaceHashCode(JSON.toJSONString(objectVO, true))); } @Test @@ -364,23 +485,23 @@ public class ObjectRenderTest { ObjectVO objectVO = objectInspector.inspect(nestedClass, 4); printObject(objectVO); - Assert.assertTrue(replaceHashCode(ObjectRenderer.render(objectVO)).contains("@NestedClass[\n" + - " code=@Integer[100],\n" + - " c1=@NestedClass[\n" + - " code=@Integer[1],\n" + - " c1=@NestedClass[\n" + - " code=@Integer[1],\n" + - " c1=@NestedClass[\n" + - " code=@Integer[1],\n" + - " c1=@NestedClass[com.taobao.arthas.core.model.ObjectRenderTest$NestedClass@ffffffff],\n" + - " c2=@NestedClass[com.taobao.arthas.core.model.ObjectRenderTest$NestedClass@ffffffff],\n" + - " ],\n" + - " c2=@NestedClass[...],\n" + - " ],\n" + - " c2=@NestedClass[...],\n" + - " ],\n" + - " c2=@NestedClass[...],\n" + - "] Number of objects exceeds limit: 10")); + Assert.assertThat(replaceHashCode(ObjectRenderer.render(objectVO)), StringContains.containsString("@ObjectRenderTest$NestedClass[\n" + + " code=@Integer[100],\n" + + " c1=@ObjectRenderTest$NestedClass[\n" + + " code=@Integer[1],\n" + + " c1=@ObjectRenderTest$NestedClass[\n" + + " code=@Integer[1],\n" + + " c1=@ObjectRenderTest$NestedClass[\n" + + " code=@Integer[1],\n" + + " c1=@ObjectRenderTest$NestedClass[com.taobao.arthas.core.model.ObjectRenderTest$NestedClass@ffffffff],\n" + + " c2=@ObjectRenderTest$NestedClass[com.taobao.arthas.core.model.ObjectRenderTest$NestedClass@ffffffff],\n" + + " ],\n" + + " c2=@ObjectRenderTest$NestedClass[...],\n" + + " ],\n" + + " c2=@ObjectRenderTest$NestedClass[...],\n" + + " ],\n" + + " c2=@ObjectRenderTest$NestedClass[...],\n" + + "] Number of objects exceeds limit: 10")); } @Test @@ -488,7 +609,11 @@ public class ObjectRenderTest { } private ObjectVO inspectObject(Object object, int expand) { - return newInspector(objectNumLimit, arrayLenLimit, stringLenLimit).inspect(object, expand); + return newInspector().inspect(object, expand); + } + + private ObjectInspector newInspector() { + return newInspector(objectNumLimit, arrayLenLimit, stringLenLimit); } private void testSimpleArray(Object array, String testJson, String testString) { @@ -516,7 +641,7 @@ public class ObjectRenderTest { private void testSimpleList(Collection collection) { ObjectVO objectVO = inspectObject(collection, 1); - Assert.assertEquals(collection.getClass().getSimpleName(), objectVO.getType()); + Assert.assertEquals(getTypeName(collection.getClass()), objectVO.getType()); printObject(objectVO); } @@ -524,7 +649,7 @@ public class ObjectRenderTest { private void testList(Collection collection, int expand) { Object[] array = collection.toArray(); ObjectVO objectVO = inspectObject(collection, expand); - Assert.assertEquals(collection.getClass().getSimpleName(), objectVO.getType()); + Assert.assertEquals(getTypeName(collection.getClass()), objectVO.getType()); Assertions.assertThat(objectVO.getValue()) .asList() @@ -541,14 +666,18 @@ public class ObjectRenderTest { printObject(objectVO); if (value != null) { - Assert.assertEquals(value.getClass().getSimpleName(), objectVO.getType()); + Assert.assertEquals(getTypeName(value.getClass()), objectVO.getType()); Assert.assertEquals(value, objectVO.getValue()); } Assert.assertEquals(test, ObjectRenderer.render(objectVO)); } + private String getTypeName(Class objClass) { + return objClass.isArray() ? objClass.getSimpleName() : objClass.getName(); + } + private String replaceHashCode(String input) { - return input.replaceAll("@[0-9a-f]+", "@ffffffff"); + return input.replaceAll("@[0-9a-f]+", "@ffffffff").replaceAll("\t", " "); } private static class NestedClass {