Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
package com.taobao.arthas.core.mcp.util;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONFactory;
import com.alibaba.fastjson2.JSONWriter;
import com.alibaba.fastjson2.filter.ValueFilter;
import com.taobao.arthas.core.GlobalOptions;
import com.taobao.arthas.core.command.model.ObjectVO;
Expand Down Expand Up @@ -93,13 +90,7 @@ private String drawObjectView(ObjectVO objectVO) {
*/
private String drawJsonView(Object object) {
try {
JSONWriter.Context context = JSONFactory.createWriteContext();
context.setMaxLevel(4097);
context.config(JSONWriter.Feature.IgnoreErrorGetter, true);
context.config(JSONWriter.Feature.ReferenceDetection, true);
context.config(JSONWriter.Feature.IgnoreNonFieldGetter, true);
context.config(JSONWriter.Feature.WriteNonStringKeyAsString, true);
return JSON.toJSONString(object, context);
return ObjectView.toJsonString(object);
} catch (Exception e) {
logger.debug("ObjectView-style serialization failed, using toString: {}", e.getMessage());
return objectToString(object);
Expand Down
24 changes: 23 additions & 1 deletion core/src/main/java/com/taobao/arthas/core/view/ObjectView.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@
import com.alibaba.arthas.deps.org.slf4j.LoggerFactory;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONWriter;
import com.alibaba.fastjson2.writer.FieldWriter;
import com.alibaba.fastjson2.writer.ObjectWriterCreator;
import com.alibaba.fastjson2.writer.ObjectWriterProvider;
import com.taobao.arthas.common.ArthasConstants;
import com.taobao.arthas.core.GlobalOptions;
import com.taobao.arthas.core.command.model.ObjectVO;
Expand All @@ -25,6 +28,25 @@ public class ObjectView implements View {
public static final int MAX_DEEP = 4;
private static final Logger logger = LoggerFactory.getLogger(ObjectView.class);
private final static int MAX_OBJECT_LENGTH = ArthasConstants.MAX_HTTP_CONTENT_LENGTH;
private static final ObjectWriterProvider JSON_OBJECT_WRITER_PROVIDER = new ObjectWriterProvider(
new ObjectWriterCreator() {
@Override
protected void setDefaultValue(List<FieldWriter> fieldWriters, Class objectClass) {
// fastjson2 默认会通过无参构造函数创建一个对象来提取字段默认值(用于 NotWriteDefaultValue 等能力),
// 这可能触发目标对象的构造逻辑(比如单例守卫、资源初始化等),在 Arthas 里属于不可接受的副作用。
// 这里直接禁用该行为,只基于现有对象进行序列化。
}
});

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);
}

private final Object object;
private final int deep;
Expand Down Expand Up @@ -54,7 +76,7 @@ public String draw() {
StringBuilder buf = new StringBuilder();
try {
if (GlobalOptions.isUsingJson) {
return JSON.toJSONString(object, JSONWriter.Feature.IgnoreErrorGetter);
return toJsonString(object);
}
renderObject(object, 0, deep, buf);
return buf.toString();
Expand Down
37 changes: 37 additions & 0 deletions core/src/test/java/com/taobao/arthas/core/view/ObjectViewTest.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.taobao.arthas.core.view;

import com.taobao.arthas.core.GlobalOptions;
import org.junit.Assert;
import org.junit.Test;

Expand Down Expand Up @@ -206,6 +207,22 @@ public void testEnumList() {
Assert.assertEquals(expected, objectView.draw());
}

@Test
public void testJsonFormatDoNotCreateNewInstance() {
boolean old = GlobalOptions.isUsingJson;
try {
JsonFormatSingleton singleton = JsonFormatSingleton.getInstance();
GlobalOptions.isUsingJson = true;

ObjectView objectView = new ObjectView(new Object[] { singleton }, 3);
String output = objectView.draw();
Assert.assertFalse(output.startsWith("ERROR DATA!!!"));
Assert.assertEquals(1, JsonFormatSingleton.constructorCalls);
} finally {
GlobalOptions.isUsingJson = old;
}
}

@Test
public void testDate() {
Date d = new Date(1531204354961L - TimeZone.getDefault().getRawOffset()
Expand Down Expand Up @@ -324,4 +341,24 @@ public void setJ(String j) {
public enum EnumDemo {
DEMO;
}

public static class JsonFormatSingleton {
private static final JsonFormatSingleton INSTANCE;
private static volatile int constructorCalls = 0;

static {
INSTANCE = new JsonFormatSingleton();
}

private JsonFormatSingleton() {
constructorCalls++;
if (constructorCalls > 1) {
throw new IllegalStateException("JsonFormatSingleton is created!");
}
}

public static JsonFormatSingleton getInstance() {
return INSTANCE;
}
}
}
Loading