diff --git a/core/src/main/java/com/taobao/arthas/core/view/ObjectView.java b/core/src/main/java/com/taobao/arthas/core/view/ObjectView.java index 232b11b471..96e4db702d 100644 --- a/core/src/main/java/com/taobao/arthas/core/view/ObjectView.java +++ b/core/src/main/java/com/taobao/arthas/core/view/ObjectView.java @@ -38,13 +38,20 @@ protected void setDefaultValue(List fieldWriters, Class objectClass }); public static String toJsonString(Object object) { - JSONWriter.Context context = new JSONWriter.Context(JSON_OBJECT_WRITER_PROVIDER); - context.setMaxLevel(4097); - context.config(JSONWriter.Feature.IgnoreErrorGetter, - JSONWriter.Feature.ReferenceDetection, - JSONWriter.Feature.IgnoreNonFieldGetter, - JSONWriter.Feature.WriteNonStringKeyAsString); - return JSON.toJSONString(object, context); + try { + JSONWriter.Context context = new JSONWriter.Context(JSON_OBJECT_WRITER_PROVIDER); + context.setMaxLevel(4097); + context.config(JSONWriter.Feature.IgnoreErrorGetter, + JSONWriter.Feature.ReferenceDetection, + JSONWriter.Feature.IgnoreNonFieldGetter, + JSONWriter.Feature.WriteNonStringKeyAsString); + return JSON.toJSONString(object, context); + } catch (StackOverflowError e) { + logger.error("ObjectView JSON serialization stackoverflow, object class: {}", object == null ? "null" : object.getClass(), e); + return "ERROR DATA!!! object class: " + (object == null ? "null" : object.getClass()) + + ", StackOverflowError: circular reference or object graph too deep. " + + "Try disabling json mode: options json false"; + } } private final Object object; diff --git a/core/src/test/java/com/taobao/arthas/core/view/ObjectViewTest.java b/core/src/test/java/com/taobao/arthas/core/view/ObjectViewTest.java index 3c814a08b7..85eca96153 100644 --- a/core/src/test/java/com/taobao/arthas/core/view/ObjectViewTest.java +++ b/core/src/test/java/com/taobao/arthas/core/view/ObjectViewTest.java @@ -393,4 +393,27 @@ public static JsonFormatSingleton getInstance() { return INSTANCE; } } + + @Test + public void testJsonModeCircularReference() { + GlobalOptions.isUsingJson = true; + try { + CircularRef a = new CircularRef("a"); + CircularRef b = new CircularRef("b"); + a.ref = b; + b.ref = a; + ObjectView objectView = new ObjectView(a, 3); + String result = objectView.draw(); + // Should not throw StackOverflowError + Assert.assertNotNull(result); + } finally { + GlobalOptions.isUsingJson = false; + } + } + + private static class CircularRef { + String name; + CircularRef ref; + CircularRef(String name) { this.name = name; } + } }