Java 中的漂亮打印 JSON

Posted

技术标签:

【中文标题】Java 中的漂亮打印 JSON【英文标题】:Pretty-Print JSON in Java 【发布时间】:2011-05-05 13:59:22 【问题描述】:

我正在使用json-simple,我需要漂亮地打印 JSON 数据(使其更易于阅读)。

我无法在该库中找到此功能。 这通常是如何实现的?

【问题讨论】:

JsonParser.parseString​(str): ***.com/a/63397831/5626568 【参考方案1】:

好像GSON 支持这个,虽然我不知道你是否想从你正在使用的库中切换。

来自用户指南:

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

【讨论】:

GSON的问题,很复杂,json-simple要容易得多。 一年多没看这个问题,不过如果你愿意稍微修改一下源代码,code.google.com/p/json-simple/issues/detail?id=22 有一些关于使用漂亮打印增强 json-simple 的信息. 得到了没有任何漂亮打印格式的字符串:( 它使用 \r\n 打印字符串 谢谢。 toString() 覆盖一行:new GsonBuilder().setPrettyPrinting().create().toJson(this);【参考方案2】:

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'

【讨论】:

好吧,我包含了将字符串解析为 JsonElement 的代码,通常您已经从之前处理 JSON 数据的工作中获得了这些代码。但我想将它包含在此处以使用法更清晰。 无需其他库即可回答 OP 的问题,因为您可以简单地访问嵌入在 Rhino(JDK 1.7 及更高版本)中的 JSON 解析器。我认为将库添加到项目中只是为了格式化一些调试输出是不可取的。 scriptEngine.eval("result = JSON.stringify(JSON.parse(jsonString), null, 2)"); 与 org.json 替代方案相比,GSON 的漂亮打印方式在转换后保持元素顺序不变。 感谢指向GsonBuilder 的指针,因为我使用的是gson.toJson(object),我只需将我的实例化从Gson gson = new Gson(); 更改为Gson gson = new GsonBuilder().setPrettyPrinting().create();,我的代码继续工作,但漂亮地打印了对象而不是一行。 JsonParser 已弃用:***.com/a/63397831/5626568【参考方案3】:

我使用org.json 内置方法来漂亮地打印数据。

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

JSON 中的字段顺序根据定义是随机的。具体顺序取决于解析器的实现。

【讨论】:

我也更喜欢这个解决方案,因为您不需要像其他答案建议的那样导入额外的依赖项。 缺少一个重要的导入 - import org.json.JSONObject; 有没有随机顺序的字段,我希望它按照我添加它们的顺序? @ThomasAdrian 使用 org.json.JSONObject 是不可能的。 Underscore-java 在格式化 json 时保持属性顺序。【参考方案4】:

在 JSONLib 中你可以使用这个:

String jsonTxt = JSONUtils.valueToString(json, 8, 4);

来自Javadoc:

【讨论】:

【参考方案5】:

在一行中使用GSON 进行漂亮的打印:

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

除了内联之外,这相当于the accepted answer。

【讨论】:

【参考方案6】:

如果您使用 Java API 进行 JSON 处理 (JSR-353) 实现,则可以在创建 JsonGeneratorFactory 时指定 JsonGenerator.PRETTY_PRINTING 属性。

以下示例最初发布在我的blog post。

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

【讨论】:

【参考方案7】:

现在这可以通过 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>

【讨论】:

虽然这个库可能有助于回答这个问题,但最好包含一个 example 来说明它如何通过一些 explanation 解决问题关于它是如何工作的。 好的,感谢您的反馈。尽管请记住,像我这样的人是志愿者,并没有因为提供保证达到质量标准的服务而获得报酬。我们的时间有限,因为我们经常在工作中,或者有家庭责任。这就是为什么读者可以使用“编辑”功能,这样我们就可以让彼此的帖子更有帮助。【参考方案8】:

一行:

String niceFormattedJson = JsonWriter.formatJson(jsonString)

json-io 库 (https://github.com/jdereg/json-io) 是一个小型 (75K) 库,除了 JDK 之外没有其他依赖项。

除了打印精美的 JSON 之外,您还可以将 Java 对象(带有循环的整个 Java 对象图)序列化为 JSON,并读入它们。

【讨论】:

【参考方案9】:

我的情况是我的项目使用不支持漂亮打印的遗留(非 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");

【讨论】:

这个太棒了,用js引擎来做,简单多了 警告:ScriptEngineManager 不是 API。【参考方案10】:

按照 JSON-P 1.0 规范 (JSR-353),给定 JsonStructureJsonObjectJsonArray)的更新解决方案可能如下所示:

import java.io.StringWriter;
import java.util.HashMap;
import java.util.Map;

import javax.json.Json;
import javax.json.JsonStructure;
import javax.json.JsonWriter;
import javax.json.JsonWriterFactory;
import javax.json.stream.JsonGenerator;

public class PrettyJson 

    private static JsonWriterFactory FACTORY_INSTANCE;

    public static String toString(final JsonStructure status) 

        final StringWriter stringWriter = new StringWriter();

        final JsonWriter jsonWriter = getPrettyJsonWriterFactory()
                .createWriter(stringWriter);

        jsonWriter.write(status);
        jsonWriter.close();

        return stringWriter.toString();
    

    private static JsonWriterFactory getPrettyJsonWriterFactory() 
        if (null == FACTORY_INSTANCE) 
            final Map<String, Object> properties = new HashMap<>(1);
            properties.put(JsonGenerator.PRETTY_PRINTING, true);
            FACTORY_INSTANCE = Json.createWriterFactory(properties);
        
        return FACTORY_INSTANCE;
    


【讨论】:

【参考方案11】:

你可以像下面这样使用 Gson

Gson gson = new GsonBuilder().setPrettyPrinting().create();
String jsonString = gson.toJson(object);

来自JSON pretty print using Gson的帖子

或者,您可以像下面这样使用 Jackson

ObjectMapper mapper = new ObjectMapper();
String perttyStr = mapper.writerWithDefaultPrettyPrinter().writeValueAsString(object);

来自Pretty print JSON in Java (Jackson)的帖子

希望对您有所帮助!

【讨论】:

【参考方案12】:

与杰克逊 (com.fasterxml.jackson.databind):

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

发件人:How to enable pretty print JSON output (Jackson)

我知道这已经在答案中,但我想在这里单独编写它,因为很可能,您已经将 Jackson 作为依赖项,因此您只需要一行额外的代码

【讨论】:

【参考方案13】:

这对我有用,使用 Jackson:

mapper.writerWithDefaultPrettyPrinter().writeValueAsString(JSONString)

【讨论】:

这个mapper 来自哪里?【参考方案14】:

大多数现有答案要么依赖于某些外部库,要么需要特殊的 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("  ");
  

【讨论】:

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

Underscore-java 有静态方法U.formatJson(json)。 支持五种格式类型:2、3、4、制表符和紧凑。 Live example

import com.github.underscore.lodash.U;

import static com.github.underscore.lodash.Json.JsonStringBuilder.Step.TABS;
import static com.github.underscore.lodash.Json.JsonStringBuilder.Step.TWO_SPACES;

public class MyClass 

    public static void main(String args[]) 
        String json = "\"Price\": "
        + "    \"LineItems\": "
        + "        \"LineItem\": "
        + "            \"UnitOfMeasure\": \"EACH\", \"Quantity\": 2, \"ItemID\": \"ItemID\""
        + "        "
        + "    ,"
        + "    \"Currency\": \"USD\","
        + "    \"EnterpriseCode\": \"EnterpriseCode\""
        + "";
        System.out.println(U.formatJson(json, TWO_SPACES)); 
        System.out.println(U.formatJson(json, TABS)); 
    

输出:


  "Price": 
    "LineItems": 
      "LineItem": 
        "UnitOfMeasure": "EACH",
        "Quantity": 2,
        "ItemID": "ItemID"
      
    ,
    "Currency": "USD",
    "EnterpriseCode": "EnterpriseCode"
  


    "Price": 
        "LineItems": 
            "LineItem": 
                "UnitOfMeasure": "EACH",
                "Quantity": 2,
                "ItemID": "ItemID"
            
        ,
        "Currency": "USD",
        "EnterpriseCode": "EnterpriseCode"
    

【讨论】:

【参考方案16】:

你可以使用小的json库

String jsonstring = ....;
JsonValue json = JsonParser.parse(jsonstring);
String jsonIndendedByTwoSpaces = json.toPrettyString("  ");

【讨论】:

【参考方案17】:

使用 org json。参考link

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

使用 Gson。参考link

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

使用杰克逊。参考link

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

使用 Genson。参考link。

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

(或)

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

jsonAdapter.toJson(jsonWriter, emp1);

json = buffer.readUtf8();

【讨论】:

感谢您的回答。如果您需要禁用 html 转义,GSON 做得很糟糕。【参考方案18】:

更新:new JsonParser().parse(...)@deprecated


基于 Gson 2.8.6 的 javadoc:

不需要实例化这个类,使用静态方法代替。

JsonParser 静态方法:

JsonParser.parseString​(jsonString);
JsonParser.parseReader​(reader);

包:

import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.JsonParser;

例子:

private Gson GSON = new GsonBuilder().setPrettyPrinting().create();
public static String getPerfectJSON(String unformattedJSON) 
    String perfectJSON = GSON.toJson(JsonParser.parseString(unformattedJSON));
    return perfectJSON;


Google Gson 使用 Maven 的依赖:

<dependency>
    <groupId>com.google.code.gson</groupId>
    <artifactId>gson</artifactId>
    <version>2.8.6</version>
</dependency>

参考:

JsonParser is deprecated

【讨论】:

【参考方案19】:

我也使用 org.json.simple 包。我只是对格式化程序进行了编码,但由于我编写的程序中的 JSON 对象中没有空值、数字或布尔值,因此我只为字符串、对象和数组进行了编码。如果有人感兴趣,就让它在公共领域。欢迎您添加缺少的数据类型(它在评论中说“它是一个字符串”)。此外,您可以添加缩进作为参数,而我的只是两个空格。请在您测试改进后重新分享。

用法printJsonObject(jsonObject, "");

功能

    public static void printJsonObject(JSONObject object, String prefix) 
        boolean notFirst = false;
        System.out.println(prefix + "");
        for (Object key : object.keySet()) 
            if (notFirst) 
                System.out.println(", ");
            
            notFirst = true;
            Object value = object.get(key);
            System.out.print(prefix + "  " + "\"" + key + "\"" + ": ");
            if (value instanceof JSONObject) 
                printJsonObject((JSONObject) value, prefix + "  ");
             else if (value instanceof JSONArray) 
                printJsonArray((JSONArray) value, prefix + "  ");
             else   // it's a string
                System.out.print("\"" + value + "\"");
            
        
        System.out.println("");
        System.out.print(prefix + "");
    

    public static void printJsonArray(JSONArray array, String prefix) 
        boolean notFirst = false;
        System.out.println("[");
        for (Object item : array) 
            if (notFirst) 
                System.out.println(", ");
            
            notFirst = true;
            if (item instanceof JSONObject) 
                printJsonObject((JSONObject) item, prefix + "  ");
             else if (item instanceof JSONArray) 
                printJsonArray((JSONArray) item, prefix + "  ");
             else 
                System.out.print(prefix + "  " + "\"" + item + "\"");
            
        
        System.out.println("");
        System.out.print(prefix + "]");
    

【讨论】:

【参考方案20】:

所以我也喜欢 json-simple 库,并研究了漂亮的打印输出。不幸的是,虽然它是open issue there,但我找不到任何代码。所以我想我会试一试,这就是我想出的(使用他们自己的来源)..

public class JsonPrinter 
  
  
  
  public static String toJson(Map<?,?> map) 
    StringBuilder out = new StringBuilder(32);
    new JsonPrinter(out).print(map);
    return out.toString();
  
  
  
  public static String toJson(List<?> list) 
    StringBuilder out = new StringBuilder(32);
    new JsonPrinter(out).print(list);
    return out.toString();
  
  
  
  
  
  
  
  
  private final Appendable out;
  private final String indentUnit;
  private final String newLine;
  
  
  private int indents;
  
  public JsonPrinter(Appendable out) 
    this(out, "  ", System.lineSeparator());
  

  /**
   * 
   */
  public JsonPrinter(Appendable out, String indentUnit, String newLine) 
    this.out = Objects.requireNonNull(out, "null out");
    this.indentUnit = Objects.requireNonNull(indentUnit, "null indentUnit");
    this.newLine = Objects.requireNonNull(newLine, "null newLine");
    
    if (!indentUnit.isBlank())
      throw new IllegalArgumentException(
          "indentUnit must be a blank sequence (quoted): '" + indentUnit + "'");
    if (!"\r\n".equals(newLine) && ! "\n".equals(newLine))
      throw new IllegalArgumentException(
          "unrecognized newLine (quoted): '" + newLine + "'");
  
  
  
  public void print(List<?> list) throws UncheckedIOException 
    try 
      assert indents == 0;
      printImpl(list);
      assert indents == 0;
     catch (IOException iox) 
      throw new UncheckedIOException("on print(List): " + list, iox);
    
  
  
  
  public void print(Map<?,?> map) throws UncheckedIOException 
    try 
      assert indents == 0;
      printImpl(map);
      assert indents == 0;
     catch (IOException iox) 
      throw new UncheckedIOException("on print(Map): " + map, iox);
    
  
  
  
  protected void printImpl(List<?> list) throws IOException 
    if (list == null) 
      out.append("null");
      return;
    
    
    
    boolean first = true;
    var iter = list.iterator();
    
    open('[');
    while (iter.hasNext()) 
      if (first)
        first = false;
      else
        out.append(',');
      
      out.append(newLine);
      appendIndents();
      
      appendValue(iter.next());
    
    close(']');
  
  
  
  protected void printImpl(Map<?, ?> map) throws IOException 
    if (map == null) 
      out.append("null");
      return;
    
    
    
    boolean first = true;
    var iter = map.entrySet().iterator();
    
    open('');
    while (iter.hasNext()) 
      if (first)
        first = false;
      else
        out.append(',');
      
      out.append(newLine);
      appendIndents();
      
      var entry = iter.next();
      print(entry.getKey().toString(), entry.getValue());
    
    close('');
  
  
  
  private void open(char c) throws IOException 
    out.append(c);
    ++indents;
  
  
  private void close(char c) throws IOException 
    --indents;
    out.append(newLine);
    appendIndents();
    out.append(c);
  
  
  private void appendIndents() throws IOException 
    for (int count = indents; count-- > 0; )
      out.append(indentUnit);
  
  
  
  
  private void print(String key, Object value) throws IOException 
    out.append('"');
    appendString(key);
    out.append('"').append(':').append(' ');
    appendValue(value);
  
  
  
  
  private void appendString(String s) throws IOException 
    for (int i = 0; i < s.length(); i++) 
      char ch = s.charAt(i);
      switch(ch)
      case '"':
        out.append("\\\"");
        break;
      case '\\':
        out.append("\\\\");
        break;
      case '\b':
        out.append("\\b");
        break;
      case '\f':
        out.append("\\f");
        break;
      case '\n':
        out.append("\\n");
        break;
      case '\r':
        out.append("\\r");
        break;
      case '\t':
        out.append("\\t");
        break;
      case '/':
        out.append("\\/");
        break;
      default:
                //Reference: http://www.unicode.org/versions/Unicode5.1.0/
        if ((ch>='\u0000' && ch<='\u001F') || (ch>='\u007F' && ch<='\u009F') || (ch>='\u2000' && ch<='\u20FF')) 
          String ss = Integer.toHexString(ch);
          out.append("\\u");
          for (int k=0; k < 4-ss.length(); k++) 
            out.append('0');
          
          out.append(ss.toUpperCase());
        
        else
          out.append(ch);
        
      
    //for
  
  
  
  private void appendValue(Object value) throws IOException 
    if (value == null) 
      out.append("null");
      
     else if (value instanceof String) 
      out.append('"');
      appendString(value.toString());
      out.append('"');
      
     else if (value instanceof Double) 
      var num = (Double) value;
      if (num.isInfinite() || num.isNaN())
        out.append("null");
      else
        out.append(value.toString());
      
     else if (value instanceof Float) 
      var num = (Float) value;
      if (num.isInfinite() || num.isNaN())
        out.append("null");
      else
        out.append(value.toString());
      
     else if (value instanceof Map) 
      printImpl((Map<?,?>) value);
      
     else if (value instanceof List) 
      printImpl((List<?>) value);
      
//     else if (value instanceof Number || value instanceof Boolean) 
//      out.append(value.toString());
      
     else 
      out.append(value.toString());
      
    
  


它适用于JSONObjectJSONArray,即使它不依赖它们.. 因为这些是常规的MapList 对象。 (事实上代码是从同一个库中提取的)。

https://github.com/crums-io/io-util/blob/master/src/main/java/io/crums/util/json/JsonPrinter.java

【讨论】:

以上是关于Java 中的漂亮打印 JSON的主要内容,如果未能解决你的问题,请参考以下文章

python python中的漂亮(或漂亮打印)JSON对象具有这一功能。在尝试了解什么时,我总是使用这个片段

在 Apache Spark 中读取漂亮的打印 json 文件

如何使用 Go 漂亮地打印 JSON?

漂亮的打印 JSON [重复]

漂亮的打印 JSON python

如何以 json 格式(双引号)漂亮地打印(人类可读的打印)Python dict? [复制]