在Java中漂亮地打印JSON

290

我正在使用,需要将JSON数据美化(使其更易读)。

在该库中未能找到此功能。 通常如何实现此功能?


JsonParser.parseString(str):https://dev59.com/Nm855IYBdhLWcg3w3IVh#63397831 - ℛɑƒæĿᴿᴹᴿ
20个回答

364

Google的GSON可以以优雅的方式实现此功能:

Gson gson = new GsonBuilder().setPrettyPrinting().create();
JsonParser jp = new JsonParser();
JsonElement je = jp.parse(uglyJsonString);
String prettyJsonString = gson.toJson(je);

或者,由于现在建议使用JsonParser的静态解析方法,因此您也可以使用它代替:

Gson gson = new GsonBuilder().setPrettyPrinting().create();
JsonElement je = JsonParser.parseString​(uglyJsonString);
String prettyJsonString = gson.toJson(je);

这是导入语句:

import com.google.gson.*;

以下是Gradle依赖项:

implementation 'com.google.code.gson:gson:2.8.7'

1
我已经包含了代码来将字符串解析为JsonElement,通常你已经在之前处理JSON数据时拥有了它。但是我想在这里包含它以使使用更清晰。 - Ray Hulha
2
可以在不需要额外的库的情况下回答问题,因为您可以直接访问嵌入在Rhino中的JSON解析器(JDK 1.7及以上版本)。我认为为了格式化一些调试输出而将库添加到项目中并不理想。 scriptEngine.eval("result = JSON.stringify(JSON.parse(jsonString), null, 2)"); - Agnes
2
与org.json替代方案相比,GSON的漂亮打印方式在转换后保持元素顺序不变。 - Aydin K.
1
感谢您指出GsonBuilder,由于我使用的是gson.toJson(object),所以我只需要将实例化从Gson gson = new Gson();更改为Gson gson = new GsonBuilder().setPrettyPrinting().create();,我的代码继续工作,但漂亮地打印了对象而不是单行。 - cptully
3
JsonParser 被弃用了:https://dev59.com/Nm855IYBdhLWcg3w3IVh#63397831 - ℛɑƒæĿᴿᴹᴿ
显示剩余4条评论

217

我使用了 org.json 的内置方法对数据进行漂亮格式化。

import org.json.JSONObject;
JSONObject json = new JSONObject(jsonString); // Convert text to object
System.out.println(json.toString(4)); // Print it with specified indentation

JSON中字段的顺序是按定义随机排列的。特定顺序取决于解析器的实现。


17
我也更喜欢这个解决方案,因为不像其他答案建议的那样需要导入额外的依赖。 - gdrt
6
缺少一个关键的导入 - import org.json.JSONObject; - MasterJoe
2
有没有任何方法可以不随机排列字段,我希望按照我添加它们的顺序排列? - Thomas Adrian
1
@ThomasAdrian, 用 org.json.JSONObject 不可能实现此功能。 - Raghu Kiran
1
Underscore-java在格式化JSON时保持属性顺序。 - Valentyn Kolesnikov
@ThomasAdrian 我已经创建了这个库的分支(https://github.com/acuna-public/LinkedJSON),它可以保存元素的顺序,只需在你的build.gradle文件中添加`api 'pro.acuna:json:1.0'`即可。 - Acuna

74

使用Jackson (com.fasterxml.jackson.databind):

ObjectMapper mapper = new ObjectMapper();
System.out.println(mapper.writerWithDefaultPrettyPrinter().writeValueAsString(jsonObject))

来源:如何启用漂亮的打印JSON输出(Jackson)

我知道这已经在答案中了,但我想在这里单独写一下,因为很有可能你已经有了Jackson依赖,所以你只需要加一行额外的代码。


这将把一个对象打印成字符串。不要认为它可以直接漂亮地打印JSON字符串。 - Cuga
5
如果你有一个字符串中的JSON,你可以这样做:mapper.writerWithDefaultPrettyPrinter().writeValueAsString(mapper.readTree(jsonString));``` - Josejulio

45

看起来GSON支持这个功能,不过我不知道你是否想要从你现在使用的库更改。

来自用户指南:

Gson gson = new GsonBuilder().setPrettyPrinting().create();
String jsonOutput = gson.toJson(someObject);

4
GSON存在的问题在于它很复杂,而json-simple则更加简单易用。 - mabuzer
1
我已经一年多没有关注这个问题了,但如果你愿意稍微修改源代码,http://code.google.com/p/json-simple/issues/detail?id=22 上有一些关于如何增强json-simple的漂亮打印信息的信息。 - BuffaloBuffalo
只得到了没有任何漂亮的格式化的字符串 :( - Cherry
它打印带有\r\n的字符串。 - Stone Jack
在一行中重写toString():new GsonBuilder().setPrettyPrinting().create().toJson(this); - KeepAtIt

32

使用org json。参考链接

JSONObject jsonObject = new JSONObject(obj);
String prettyJson = jsonObject.toString(4);

使用Gson。参考链接

Gson gson = new GsonBuilder().setPrettyPrinting().create();
String json = gson.toJson(obj);

使用Jackson。参考链接

ObjectMapper mapper = new ObjectMapper();
mapper.enable(SerializationFeature.INDENT_OUTPUT);
String json = mapper.writeValueAsString(obj);

使用Genson。参考链接
Genson prettyGenson = new GensonBuilder().useIndentation(true).create();
String prettyJson = prettyGenson.serialize(obj);

使用javax.json。参考link

Map<String, Boolean> config = new HashMap<>();

config.put(JsonGenerator.PRETTY_PRINTING, true);

JsonWriterFactory writerFactory = Json.createWriterFactory(config);
Writer writer = new StringWriter();

writerFactory.createWriter(writer).write(jsonObject);

String json = writer.toString();

使用 Moshi 库。参考 link

String json = jsonAdapter.indent("  ").toJson(emp1);

(OR)

Buffer buffer = new Buffer();
JsonWriter jsonWriter = JsonWriter.of(buffer);
jsonWriter.setIndent("   ");

jsonAdapter.toJson(jsonWriter, emp1);

json = buffer.readUtf8();

感谢您的回答。如果您需要禁用HTML转义,GSON做得非常糟糕。 - Austin Poole

23
如果您正在使用Java API进行JSON处理(JSR-353)实现,则可以在创建JsonGeneratorFactory时指定JsonGenerator.PRETTY_PRINTING属性。以下示例最初发布在我的博客文章上。
import java.util.*;
import javax.json.Json;
import javax.json.stream.*;

Map<String, Object> properties = new HashMap<String, Object>(1);
properties.put(JsonGenerator.PRETTY_PRINTING, true);
JsonGeneratorFactory jgf = Json.createGeneratorFactory(properties);
JsonGenerator jg = jgf.createGenerator(System.out);

jg.writeStartObject()                    // {
    .write("name", "Jane Doe")           //    "name":"Jane Doe",
    .writeStartObject("address")         //    "address":{
        .write("type", 1)                //        "type":1,
        .write("street", "1 A Street")   //        "street":"1 A Street",
        .writeNull("city")               //        "city":null,
        .write("verified", false)        //        "verified":false
    .writeEnd()                          //    },
    .writeStartArray("phone-numbers")    //    "phone-numbers":[
        .writeStartObject()              //        {
            .write("number", "555-1111") //            "number":"555-1111",
            .write("extension", "123")   //            "extension":"123"
        .writeEnd()                      //        },
        .writeStartObject()              //        {
            .write("number", "555-2222") //            "number":"555-2222",
            .writeNull("extension")      //            "extension":null
        .writeEnd()                      //        }
    .writeEnd()                          //    ]
.writeEnd()                              // }
.close();

21

使用GSON一行代码实现漂亮的打印:

System.out.println(new GsonBuilder().setPrettyPrinting().create().toJson(new JsonParser().parse(jsonString)));

除了内联之外,这与被接受的回答等效。


19

我的情况是,我的项目使用了一个不支持漂亮打印的旧版(non-JSR)JSON解析器。然而,我需要生成漂亮打印的JSON样本;只要您使用的是Java 7及以上版本,就可以在不添加任何额外库的情况下实现这一点:

ScriptEngineManager manager = new ScriptEngineManager();
ScriptEngine scriptEngine = manager.getEngineByName("JavaScript");
scriptEngine.put("jsonString", jsonStringNoWhitespace);
scriptEngine.eval("result = JSON.stringify(JSON.parse(jsonString), null, 2)");
String prettyPrintedJson = (String) scriptEngine.get("result");

3
太棒了,使用 JavaScript 引擎来完成它,会简单得多。 - med116
警告:如果您关心的话,ScriptEngineManager不是API。 - nclark

18
大多数现有的答案都依赖于某些外部库,或需要特殊的Java版本。以下是一段简单的代码,用于漂亮地打印JSON字符串,仅使用通用的Java API(适用于Java 7及更高版本;尚未尝试较旧版本)。
基本思路是根据JSON中的特殊字符触发格式化。例如,如果观察到'{'或'[',则该代码将创建一个新行并增加缩进级别。
免责声明:我仅针对一些简单的JSON情况进行了测试(基本键值对,列表,嵌套JSON),因此可能需要为更通用的JSON文本(如带引号的字符串值,或特殊字符(\n,\t等))做出一些调整。
/**
 * A simple implementation to pretty-print JSON file.
 *
 * @param unformattedJsonString
 * @return
 */
public static String prettyPrintJSON(String unformattedJsonString) {
  StringBuilder prettyJSONBuilder = new StringBuilder();
  int indentLevel = 0;
  boolean inQuote = false;
  for(char charFromUnformattedJson : unformattedJsonString.toCharArray()) {
    switch(charFromUnformattedJson) {
      case '"':
        // switch the quoting status
        inQuote = !inQuote;
        prettyJSONBuilder.append(charFromUnformattedJson);
        break;
      case ' ':
        // For space: ignore the space if it is not being quoted.
        if(inQuote) {
          prettyJSONBuilder.append(charFromUnformattedJson);
        }
        break;
      case '{':
      case '[':
        // Starting a new block: increase the indent level
        prettyJSONBuilder.append(charFromUnformattedJson);
        indentLevel++;
        appendIndentedNewLine(indentLevel, prettyJSONBuilder);
        break;
      case '}':
      case ']':
        // Ending a new block; decrese the indent level
        indentLevel--;
        appendIndentedNewLine(indentLevel, prettyJSONBuilder);
        prettyJSONBuilder.append(charFromUnformattedJson);
        break;
      case ',':
        // Ending a json item; create a new line after
        prettyJSONBuilder.append(charFromUnformattedJson);
        if(!inQuote) {
          appendIndentedNewLine(indentLevel, prettyJSONBuilder);
        }
        break;
      default:
        prettyJSONBuilder.append(charFromUnformattedJson);
    }
  }
  return prettyJSONBuilder.toString();
}

/**
 * Print a new line with indention at the beginning of the new line.
 * @param indentLevel
 * @param stringBuilder
 */
private static void appendIndentedNewLine(int indentLevel, StringBuilder stringBuilder) {
  stringBuilder.append("\n");
  for(int i = 0; i < indentLevel; i++) {
    // Assuming indention using 2 spaces
    stringBuilder.append("  ");
  }
}

1
第一次阅读时,我对这个建议非常不满意,但在阅读了所有答案后,我认为这是最好的解决方案。至少,如果只是为了一些调试输出,并且您不想拖入可能稍后再次删除的依赖项。非常感谢! - user2081279

10

现在可以使用JSONLib库来实现这一点:

http://json-lib.sourceforge.net/apidocs/net/sf/json/JSONObject.html

如果(仅当)您使用重载的toString(int indentationFactor)方法而不是标准的toString()方法。

我已经在以下API版本上验证了这一点:

<dependency>
  <groupId>org.json</groupId>
  <artifactId>json</artifactId>
  <version>20140107</version>
</dependency>

3
虽然这个库可能有助于回答问题,但最好还是包含一个_示例_,说明它如何适用于问题,并提供一些关于其工作原理的_解释_。 - spongebob
1
好的,感谢您的反馈。但请记住,像我这样的人是志愿者,没有得到报酬来提供保证符合质量标准的服务。我们时间有限,因为我们经常在工作中,或者有家庭职责。这就是为什么“编辑”对读者可用,这样我们可以使彼此的帖子更有帮助。 - Sridhar Sarnobat

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接