当前位置: 首页 > 知识库问答 >
问题:

序列化Jackson JSON树模型时排除NullNode

阳福
2023-03-14

我有一个pojo类型,需要在序列化时将特定的数值设置为特殊字符串。这些值将始终为空,可能深入到层次结构中。

为了做到这一点,我首先将pojo转换为一个JsonNode,保留空值以保持属性顺序,然后按照结构中的路径设置一些字符串并根据需要创建节点。最后,我让ObjectMapper将JsonNode序列化为字符串。逻辑看起来像这样:

ObjectMapper nonNullMapper = new ObjectMapper();
nonNullMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);

ObjectMapper includeAllMapper = new ObjectMapper();
includeAllMapper.setSerializationInclusion(JsonInclude.Include.ALWAYS);

// NullNodes create stubs to maintain property order
JsonNode node = includeAllMapper.valueToTree(pojoInstance);
insertStrings(node);

String json = nonNullMapper.writeValueAsString(node); 
// Halp, there's still nulls

注意,我知道有一个@JsonInclude注释,所以我实际上不需要两个映射器,但事实证明,我想序列化pojo实例,而不在其他地方使用null,所以据我所知,我无法使用它。

无论如何,如何避免将NullNodes序列化到json字符串中?到目前为止,我发现了两种方法:

  1. 使用SerializationFeature将其转换为映射,然后序列化为字符串。写入空映射值已禁用。这似乎效率低下,而且很粗糙
  2. 在序列化JsonNode之前手动删除NullNode实例。考虑到对POJO和maps排除空值的支持,似乎没有必要这样做,而且它还增加了(也许?)不必要的复杂性

我尝试为NullNode注册一个JsonSerializer,但它似乎没有被使用。我注意到,NullNode本身实现了JsonSerializable,它只是委托给SerializerProvider的空值序列化程序。我不太愿意尝试覆盖它,我觉得空过滤应该在值序列化之前进行,但我没有深入了解它的工作原理

有更好的办法吗?

共有3个答案

倪鹏
2023-03-14

我猜您的问题是由于您试图获取已序列化对象的字符串值。

当您没有序列化任何东西(因为您已经用不同的ObjectMapper序列化了它)时,setSerialization包容参数应该做什么?

您可以尝试让这些字段变得特别(一个扩展整数的非常简单的POJO),并为它们创建自定义转换器,当它们为空时返回所需的值。

请参见objectMapper。注册表模块。您只需要为创建的新特殊对象类型创建一个SimpleModule和一些JsonSerializers。它们可能非常简单:

public class SpecialOverriddenNumberSerializer
  extends JsonSerializer<SpecialOverriddenNumber>
{
  private final static String ILLEGAL_VALUE_TEXT = "Some text";

  @Override
  public void serialize (
    SpecialOverriddenNumber value,
    JsonGenerator jgen,
    SerializerProvider provider )
    throws IOException, JsonProcessingException
  {
    // ILLEGAL_VALUE could be equivalent to Integer.MAX_VALUE or something
    // (possibly even null -- though I'm not sure if that would work well
    // with the NON_NULL serialization setting)
    if(value == SpecialOverriddenNumber.ILLEGAL_VALUE)
    {
      // jgen.writeNull();
      jgen.writeString(ILLEGAL_VALUE_TEXT);
    }
    else
    {
      jgen.writeNumber(value);
    }
  }
}

如果您还需要反序列化器,您可以简单地创建一个JsonDeserializer,如果它读取ILLEGAL_VALUE_TEXT,则返回null

水渊
2023-03-14

我不知道有什么好的解决方案,但我只是想指出,JSON树模型(JsonNode)用于表示精确的JSON结构;因此,很少有用于过滤或转换的一般特征被应用。它非常接近所见即所得。

正因为如此,我可能宁愿只遍历树并显式地修剪NullNodes。试图配置杰克逊本身来做这件事最终比显式地删除节点要做更多的工作。

仇和蔼
2023-03-14

关于@StaxMan的答案,这里有一些代码可以删除空节点:

public static void stripNulls(JsonNode node) {
    Iterator<JsonNode> it = node.iterator();
    while (it.hasNext()) {
        JsonNode child = it.next();
        if (child.isNull())
            it.remove();
        else
            stripNulls(child);
    }
}
 类似资料:
  • 这是我的视图模型: 我正在用数据加载视图模型,并将其传递给视图并序列化它: 但是我得到了这个错误 “类型”系统。网状物无法序列化HttpPostedFileWrapper“”。考虑使用DATACONTractAttor属性对其进行标记,并标记要使用DATAMEMBAREATE属性序列化的所有成员。如果类型是集合,请考虑用CopyDATAcNoTractAttor标记它。见微软。其他受支持类型的NE

  • 我有两种型号: 产品,它有字段 库存,具有产品标识和数量字段 我想按排序字段(ASC)获取订购的产品,但库存量等于0的产品需要位于列表的末尾。 例如。 产品介绍 股票 预期列表(产品ID)-4、1、2、3 我已经为我需要做的事情编写了SQL查询。 有没有一种方法可以使用雄辩模型的作用域来获得此类列表? 使现代化 解决方案。

  • 主要内容:使用excludeFieldsWithModifiers()方法,使用@Expose注解默认情况下,GSON排除序列化/反序列化过程中的瞬态和静态字段。 我们来看看下面的例子。 示例 创建一个名为的Java类文件:GsonTester.java - 执行上面示例代码,得到以下结果 - 使用excludeFieldsWithModifiers()方法 GsonBuilder使用序列化/反序列化过程中的方法提供对使用特定修饰符排除字段的控制。 看下面的例子。 示例 创建一个名为的Java

  • NowCoder 题目描述 请实现两个函数,分别用来序列化和反序列化二叉树。 解题思路 // java private String deserializeStr; public String Serialize(TreeNode root) { if (root == null) return "#"; return root.val + " " + Seria

  • 我正试图弄清楚如何使用树遍历来唯一地识别一棵树,问题的关键似乎是这棵树是香草二叉树(BT),还是它也有更严格的规定二进制搜索树(BST)。这篇文章似乎表明,对于BT,单一的顺序、前序和后序遍历不会唯一地识别树(在这种情况下唯一地意味着键的结构和值)。以下是文章的快速摘要: BTs 1。我们可以用前序-序和后序-序唯一地重构BT。 2。如果我们还规定遍历跟踪节点的空子节点,那么我们也可以使用前序后序

  • 问题内容: 我有一个包含a 和a的类。现在,我想使用gson序列化对象,但排除该字段。 如您所见,我已经尝试使用,但是似乎没有任何作用。另外,我已经将该字段设置为私有,因为我认为这会“覆盖” 但运行以下代码: 仍然会导致以下文件内容没有错误: 那我在做什么错?我现在一无所知,并且希望得到任何帮助,因为这似乎行不通。 提前致谢。 问题答案: 为了获得此结果,您需要使用注释所有字段: 并将Gson配置