杰克逊:将null对象序列化为空

时间:2017-08-08 10:27:22

标签: java-8 jackson jackson-modules

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

例如我有以下模型:

@Scheduled(cron = "${FileConfig.FileEnum.getScheduleTime()}" )
public void scheduleFetchFiles() {

...//method body

}

并且有可能只填充第一个实例:

在通常的情况下,它将被序列化如下:

class First {

    private firstField;
    private secondField;
    etc...
}

class Second {

    private firstField;
    private secondField;
    etc...
}

class General {

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

但我的目标是将General类序列化为:

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

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

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

但是这种方法会对现有模型造成太多变化,我不确定它是最好的方法。是否可以创建一些自定义的自定义序列化程序?

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

因此,主要思想是创建能够检查实例是否为null的序列化程序,如果它为null,它应该能够使用默认构造函数创建新实例,注意:此序列化程序不应该基于特定的class General { private First first = new First(); private Second second = new Second() etc... } 类,它应该适用于除了简单类型之外将被序列化的任何对象。

1 个答案:

答案 0 :(得分:2)

是的,可以创建一个使用反射来执行此操作的自定义序列化程序。您可以通过扩展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();
    }
}

这取决于每个字段都有一个公共默认构造函数。您可能希望捕获一些异常,而不是像我已经完成的那样将它们声明为抛出签名。

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

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