如何漂亮地打印一个复杂的 Java 对象(例如,带有对象集合的字段)?

How to pretty print a complex Java object (e.g. with fields that are collections of objects)?

我正在寻找一个库函数 (最好来自常用框架,例如 Spring、Guava、Apache Commons 等) 可以很好地打印值任何 Java 对象。

这是一个一般性问题,而不是一个具体问题。在 Whosebug 上看到过类似的问题,其常见答案是 "implement your own toString() method on the class" 但此选项并不总是实用 - 我正在寻找对我遇到的任何对象执行此操作的通用方法,这可能源自第三方代码。另一个建议是使用 Apache Commons 中的 RefectionToStringBuilder,例如:

new ReflectionToStringBuilder(complexObject, new RecursiveToStringStyle()).toString()

但这用途有限 - 例如当它遇到一个集合时,它倾向于输出这样的东西:

java.util.ArrayList@fcc7ab1[size=1]

一个实际用例示例是记录一个 Iterable<PushResult> returned from JGit's pushCommand.call() 方法 - 如果发布一个答案,请确保它适用于此以及任何其他复杂对象。

您可以使用 JSON(或其他格式)映射器来漂亮地打印您的对象。它应该可以处理大多数 "standard" 字段(基元、字符串、集合、映射、数组等),如果不能,您可以随时添加自定义序列化程序。

例如,对于 Jackson,它可以像这样简单:

public static void main(String... args) throws Exception {
  ObjectMapper om = new ObjectMapper();
  om.enable(SerializationFeature.INDENT_OUTPUT); //pretty print
  String s = om.writeValueAsString(new Pojo());
  System.out.println(s);
}


static class Pojo {
  private int id = 1;
  private List<String> list = Arrays.asList("A", "B");
  //getters etc.
}

该代码输出:

{
  "id" : 1,
  "list" : [ "A", "B" ]
}

您可以尝试使用 Gson。它还序列化数组、映射或其他任何内容....

MyObject myObject = new MyObject();
Gson gson = new GsonBuilder().setPrettyPrinting().serializeNulls().create();
gson.toJson(myObject);

反序列化使用:

gson.fromJson(MyObject.class);

对于打字地图,请参阅此答案:Gson: Is there an easier way to serialize a map

您可以使用 GSON 将您的对象转换为字符串。这将适用于所有对象,

Gson gson = new Gson();
System.out.println(gson.toJson(objectYouWantToPrint).toString());

您可以使用 Jackson ObjectMapper class 用于与 json 绑定数据。你可以像下面这样使用它:

ObjectMapper mapper = new ObjectMapper();

您可以将 json 保存到如下对象中

Object json = mapper.readValue(input,object.class);

你可以把它写在字符串变量中

String prettyJson = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(json);

它应该可以正常工作。

在不使用外部库的情况下对任何对象执行此操作的一种可能方法是使用通用类型的反射。在下面的代码片段中,我们简单地访问每个字段(包括私有字段)并打印它们的名称和值:

public static <T> String printObject(T t) {
    StringBuilder sb = new StringBuilder();

    for (Field field : t.getClass().getDeclaredFields()) {
        field.setAccessible(true);

        try {
            sb.append(field.getName()).append(": ").append(field.get(t)).append('\n');
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    return sb.toString();
}

可以将此方法放在实用程序中 class 以便于访问。

如果对象的任何字段没有覆盖 Object#toString,它将简单地打印对象的类型及其 hashCode。

示例:

public class Test {

    private int x = 5;

    private int y = 10;

    private List<List<Integer>> list = Arrays.asList(Arrays.asList(1, 2, 3), Arrays.asList(4, 5, 6));

}

>> printObject(new Test());
>>
>> x: 5
>> y: 10
>> list: [[1, 2, 3], [4, 5, 6]]