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

时间:2014-02-02 14:05:41

标签: java json jackson

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

为了实现这一点,我首先将pojo转换为JsonNode,其中null保持不变以保留属性顺序,然后我按照结构中的路径设置一些字符串并根据需要创建节点。最后,我让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实例,所以我不能使用它据我所知。

无论如何,我怎样才能避免将NullNodes序列化为我的json字符串?到目前为止,我找到了两种方法:

  1. 转换为Map,然后序列化为String,禁用SerializationFeature.WRITE_NULL_MAP_VALUES。这似乎效率低,而且很容易。
  2. 在序列化JsonNode之前手动删除NullNode实例。看起来它不应该是必要的,因为支持为pojos和地图排除空值,并且它增加了(可能是?)不必要的复杂性。
  3. 我尝试为JsonSerializer注册NullNode,但似乎没有被使用。我注意到NullNode本身实现了JsonSerializable,它只是委托给SerializerProvider的空值序列化程序。我犹豫是否试图覆盖这个,我觉得应该在序列化值之前进行空过滤,但我没有深入挖掘以确切了解它是如何工作的。

    有更好的方法吗?

3 个答案:

答案 0 :(得分:2)

我不知道一个好的解决方案,但我想我指出JSON树模型(JsonNode)用于呈现精确的JSON结构;因此,应用了很少的用于过滤或变换的一般特征。它与WYSIWYG非常接近。

因此,我可能只是遍历树并明确修剪NullNode。试图配置Jackson本身来做到这一点最终会比明确删除节点更多的工作。

答案 1 :(得分:2)

继@ StaxMan的回答,这里有一些修剪NullNodes的代码:

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

答案 2 :(得分:1)

我猜你的问题是由于你试图获得已经序列化的对象的String值。

当您没有序列化任何内容时,setSerializationInclusion参数应该做什么(因为您已经使用不同的ObjectMapper对其进行了序列化)?

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

请参阅objectMapper.registerModule。您只需要为您创建的新特殊对象类型创建SimpleModule和一些JsonSerializer。它们可能非常简单:

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,如果它显示为null,则会返回ILLEGAL_VALUE_TEXT