java-8 - Jackson:将空对象序列化为空

标签 java-8 jackson jackson-modules

我有巨大的 json 文档和映射到该 json 的适当 jaskson 模型。在某些情况下,由于某些数据不存在,无法使用所有对象构建所需的 json 文档。

例如我有以下模型:

class First {

    private firstField;
    private secondField;
    etc...
}

class Second {

    private firstField;
    private secondField;
    etc...
}

class General {

    private First first;
    private Second second;
    etc...
}

并且可以仅填充第一个实例:

通常情况下,它会被序列化,如下所示:

{
   "first":{
      "firstField":"some_value",
      "secondField":"some_value"
   },
   "second":null
}

但我的目标是序列化 General 类,如下所示:

{  
   "first":{  
      "firstField":"some_value",
      "secondField":"some_value"
   },
   "second":{  
      "firstField":"null",
      "secondField":"null"
   }
}

可以通过在 General 类中进行以下更改来实现此目的,以便默认使用默认构造函数初始化其成员:

class General {

        private First first = new First();
        private Second second = new Second()
        etc...
    }

但是这种方法会导致现有模型发生太多变化,我不确定这是最好的方法。是否可以创建一些自定义序列化器来自行完成此操作?

根据https://stackoverflow.com/users/1898563/michael编辑建议:

因此,主要思想是创建序列化程序,该序列化程序能够检查实例是否为空,如果为空,它应该能够使用默认构造函数创建新实例,注意:此序列化程序不应基于特定的 Second 类,它应该适用于除简单类型之外的任何要序列化的对象。

最佳答案

是的,可以创建一个使用反射来执行此操作的自定义序列化程序。您可以通过扩展StdSerializer来做到这一点。您的实现可能如下所示:

public class NullSerializer<T> extends StdSerializer<T> {

    public NullSerializer() {
        this(null);
    }

    public NullSerializer(Class<T> t) {
        super(t);
    }

    @Override
    public void serialize(T item, JsonGenerator jgen, SerializerProvider provider)
            throws IOException, JsonProcessingException,
            IllegalAccessException, NoSuchMethodException, InvocationTargetException, InstantiationException)
    {

        jgen.writeStartObject();

        // For all fields of the class you're serializing
        for (final Field field : item.getClass().getDeclaredFields())
        {
            field.setAccessible(true);

            Object value = field.get(item);

            // if the value is null, create a new instance
            if (value == null)
            {  
                value = field.getType().getConstructor().newInstance();
            }

            // write it
            jgen.writeObject(value);
        }

        jgen.writeEndObject();
    }
}

这依赖于每个字段都有一个公共(public)默认构造函数。您可能想要捕获一些异常,而不是像我所做的那样将它们声明为在签名中抛出。

您需要向 ObjectMapper 注册此序列化程序。 This article解释了如何做到这一点。


我认为这不是一个特别优雅的解决方案,但它应该满足您的要求。我首先会避免使用可为空的字段,但在您的情况下这可能是不可能的。

关于java-8 - Jackson:将空对象序列化为空,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45565848/

相关文章:

java - Lambda 表达式和高阶函数

java-8 - 为什么用于创建谓词的函数应该定义为静态的?

java - Jackson 的 StdDeserializer 的构造函数中使用的 Class<?> vc 或 JavaType valueType 是什么

java - 在 JSTL <fmt :formatDate> action 中使用 java.time.LocalDate

java - Jackson 映射中标准属性和动态属性的混合

java - com.fasterxml.jackson.core.JsonParseException : Unexpected character ('\' (code 92)) [Java]

Java - 要 Set<T> 的 Json 字符串

java - 在 Java 中反序列化人类可读持续时间的最简单方法是什么?

c# - 在 C# 中使用 lambda 的 Enumerable.Select 的 Java 等价物是什么?