当前位置: 首页 > 面试题库 >

在Jackson中将JsonNode序列化为非常特定的JSON格式

陆烨烁
2023-03-14
问题内容

我有JsonNode要打印的结果。到目前为止,我正在使用:

ObjectMapper mapper = new ObjectMapper();
mapper.enable(SerializationFeature.INDENT_OUTPUT);
File outputFile = new File(
    getCurOutputDir(), String.format("out.json", getClass().getSimpleName())
);
mapper.writeValue(new FileOutputStream(outputFile), resultNode);

输出类似:

{
  "A" : [ {
    "Ai" : {
      "Ai1" : 42,
      "Ai2" : 55
    }
  } ],
    "B" : [ 86 ]
}

但我需要采用以下特定格式:

{
  "A" : [ 
    {
      "Ai" : {
        "Ai1" : 42,
        "Ai2" : 55
      }
    } 
  ],
    "B" : [
      86 
    ]
}

对于上下文,我要从过渡JSONObject到Jackson,因此第二个输出是的输出JSONObject.serialize()

另外,上面列出的每种格式都有名称吗?似乎它遵循不同的标准。


问题答案:

您可以自定义Jackson如何缩进输出。根据您使用的Jackson版本,有多种实现方法。

杰克逊2.5及更高版本

请执行下列操作:

DefaultPrettyPrinter printer = new DefaultPrettyPrinter();
Indenter indenter = new DefaultIndenter();
printer.indentObjectsWith(indenter); // Indent JSON objects
printer.indentArraysWith(indenter);  // Indent JSON arrays

ObjectMapper mapper = new ObjectMapper();
mapper.writer(printer).writeValue(new FileOutputStream(outputFile), node);

默认情况下,将使用2个空格。对于不同数量的空格,请使用DefaultIndenter接收字符串以缩进级别和行分隔符的构造函数:

Indenter indenter = new DefaultIndenter("      ", DefaultIndenter.SYS_LF);

杰克逊2.4及更低版本

请执行下列操作:

DefaultPrettyPrinter printer = new DefaultPrettyPrinter();
Indenter indenter = new Lf2SpacesIndenter();
printer.indentObjectsWith(indenter); // Indent JSON objects
printer.indentArraysWith(indenter);  // Indent JSON arrays

ObjectMapper mapper = new ObjectMapper();
mapper.writer(printer).writeValue(new FileOutputStream(outputFile), node);

Lf2SpacesIndenter被限制在2个空格,你不能改变它。

如果需要不同数量的空格,则需要编写自定义实现。这是使用与DefaultIndenterJackson
2.5中引入的代码相同的代码的代码:

/**
 * Default linefeed-based indenter.
 */
public class CustomSpaceIndenter extends DefaultPrettyPrinter.NopIndenter {

    public final static String SYS_LF;
    static {
        String lf;
        try {
            lf = System.getProperty("line.separator");
        } catch (Throwable t) {
            lf = "\n"; // fallback when security manager denies access
        }
        SYS_LF = lf;
    }

    public static final CustomSpaceIndenter SYSTEM_LINEFEED_INSTANCE = 
            new CustomSpaceIndenter("  ", SYS_LF);

    /**
     * We expect to rarely get indentation deeper than this number of levels,
     * and try not to pre-generate more indentations than needed.
     */
    private final static int INDENT_LEVELS = 16;
    private final char[] indents;
    private final int charsPerLevel;
    private final String eol;

    /**
     * Indent with two spaces and the system's default line feed
     */
    public CustomSpaceIndenter() {
        this("  ", SYS_LF);
    }

    /**
     * Create an indenter which uses the <code>indent</code> string to indent one level
     *  and the <code>eol</code> string to separate lines.
     */
    public CustomSpaceIndenter(String indent, String eol)  {
        charsPerLevel = indent.length();
        indents = new char[indent.length() * INDENT_LEVELS];
        int offset = 0;
        for (int i=0; i<INDENT_LEVELS; i++) {
            indent.getChars(0, indent.length(), indents, offset);
            offset += indent.length();
        }
        this.eol = eol;
    }

    public CustomSpaceIndenter withLinefeed(String lf) {
        if (lf.equals(eol)) {
            return this;
        }
        return new CustomSpaceIndenter(getIndent(), lf);
    }

    public CustomSpaceIndenter withIndent(String indent) {
        if (indent.equals(getIndent())) {
            return this;
        }
        return new CustomSpaceIndenter(indent, eol);
    }

    public String getEol() {
        return eol;
    }

    public String getIndent() {
        return new String(indents, 0, charsPerLevel);
    }

    @Override
    public boolean isInline() { 
        return false;
    }

    @Override
    public void writeIndentation(JsonGenerator jg, int level) throws IOException {
        jg.writeRaw(eol);
        if (level > 0) { // should we err on negative values (as there's some flaw?)
            level *= charsPerLevel;
            while (level > indents.length) { // unlike to happen but just in case
                jg.writeRaw(indents, 0, indents.length); 
                level -= indents.length;
            }
            jg.writeRaw(indents, 0, level);
        }
    }
}

可以如下使用:

Indenter indenter = new CustomSpaceIndenter("      ", CustomSpaceIndenter.SYS_LF);


 类似资料:
  • 有没有一种方法可以使用Jackson JSON处理器来执行自定义字段级别的序列化?例如,我想让 注意,age=25被编码为数字,而favoritenumber=123被编码为字符串。Jackson将编组为一个数字。在这种情况下,我希望将favoriteNumber编码为字符串。

  • 问题内容: 使用Jackson 2,我正在寻找一种 通用的 方式将对象序列化为单个值(然后序列化它们,然后再填充该单个字段),而不必重复创建JsonSerializer / JsonDeserializer来处理每种情况。@JsonIdentityInfo批注非常接近,但由于我知道,它将始终对完整的子对象进行序列化,因此略微遗漏了该标记。 这是我想做的一个例子。给定的类: 我希望Order可以序列

  • 有没有一个Jackson注释允许将数组反序列化到我的POJO的特定字段中?我可以用自定义的反序列化器很容易地做到这一点,但我希望用类内联的方式来完成。 例如,我从Elasticsearch返回了以下JSON。 我的POJO如下: 我希望“排序”数组(在数组[0]中总是有一个long,在数组[1]中总是有一个String)被反序列化如下: 我发现了另一个问题,唯一的答案是自定义的反序列化器,如果可以

  • 我试图实现的是在自定义反序列化器中将JsonNode转换为POJO(=反序列化它)。 大多数其他答案建议使用对象映射器,但我在反序列化方法中没有对象映射器。 这是我的自定义反序列化程序: (

  • 我需要反序列化以下json: 将它的< code>id属性设置为< code>foo_id json属性。 我需要在自定义反序列化程序中执行此操作。实现这一点最简单的方法是什么? 我想以某种方式将json“转换”为 然后将此委托给杰克逊。 在本例中,对象的类型为Foo,但其他对象可能不属于此类。另外,在本例中,json是一个数字,但如果它也是一个字符串,我希望支持。所以,我需要一种通用的方法来做到

  • 我试图用Jackson库创建复杂类的对象。每个对象都有一个模式,反序列化器需要使用该模式来解释JSON。我的问题是如何向反序列化器提供模式? 反序列化程序扩展了类JSONDeserializer,该类具有无参数构造函数和必须重写的抽象方法反序列化(解析器、上下文)。我想改用另一种方法反序列化(解析器、上下文、值),其中值是部分构造的对象,其中包括模式。也就是说,反序列化方法可以调用value。sc