使用Jackson反序列化JSON时的隐式默认值

时间:2015-04-28 20:04:00

标签: java json jackson deserialization

在反序列化各种JSON消息时,我想为某种类型的属性提供默认值。简单地指定Class中的值是generally suggested,但是如果必须在许多类中执行此操作,则这很容易出错。您可能会忘记一个并以null而不是默认值结束。我的目的是将每个属性Optional<T>设置为Optional.absent。由于null正是Optional试图消除的,因此将其与杰克逊一起使用已被证明令人沮丧。

Jackson的大多数功能允许您自定义反序列化过程,重点关注作为输入的JSON,而不是实例化您要反序列化的Object的过程。我似乎最接近一般解决方案是建立我自己的ValueInstantiator,但我还有两个问题:

  • 如何让它仅将Optional实例化为absent,但不会干扰实例化过程的其余部分?
  • 如何将最终结果汇总到我的ObjectMapper

更新:我想澄清一下,我正在寻找一个涉及修改包含{{1}的每个类的解决方案}&#39;第我反对违反DRY原则。每当我们将Optional添加到新的或现有的班级时,我或我的同事都不应该考虑做额外的事情。我希望能够说,&#34;将每个Class中的每个可选字段反序列化为预先填充Optional&#34;,只进行一次,然后完成。

这意味着以下内容:

  • 抽象父类(需要声明)
  • 自定义Builder / Creator / JsonDeserializer(需要在每个适用的类上添加注释)
  • MIXIN&#39; S?我尝试了这个,结合反思,但我不知道如何进入我被混入的一级......

2 个答案:

答案 0 :(得分:2)

特别是对于java.lang.Optional,杰克逊人自己有一个模块:https://github.com/FasterXML/jackson-datatype-jdk8

Guava Optional由https://github.com/FasterXML/jackson-datatype-guava

涵盖

它将为null创建一个Optional.absent,但不会为缺少的JSON值创建: - (。

请参阅https://github.com/FasterXML/jackson-databind/issues/618https://github.com/FasterXML/jackson-datatype-jdk8/issues/2

因此,您应该像初始化集合一样初始化Optionals。这是一个很好的做法,所以你应该能够强制执行它。

private Optional<Xxx> xxx = Optional.absent();
private List<Yyy> yyys = Lists.newArrayList();

答案 1 :(得分:1)

您可以编写自定义反序列化程序来处理默认值。实际上,您将为要反序列化的对象类型扩展适当的反序列化器,获取反序列化的值,如果它null只返回适当的默认值。

这是使用字符串快速完成此操作的方法:

public class DefaultStringModule extends SimpleModule {
    private static final String NAME = "DefaultStringModule";

    private static final String DEFAULT_VALUE = "[DEFAULT]";

    public DefaultStringModule() {
        super(NAME, ModuleVersion.instance.version());
        addDeserializer(String.class, new DefaultStringDeserializer());
    }

    private static class DefaultStringDeserializer extends StdScalarDeserializer<String> {
        public DefaultStringDeserializer() {
            super(String.class);
        }

        public String deserialize(JsonParser jsonParser, DeserializationContext context) throws IOException, JsonProcessingException {
            String deserialized = jsonParser.getValueAsString();

            // Use a default value instead of null
            return deserialized == null ? DEFAULT_VALUE : deserialized;
        }

        @Override
        public Object deserializeWithType(JsonParser jp, DeserializationContext ctxt, TypeDeserializer typeDeserializer) throws IOException {
            return deserialize(jp, ctxt);
        }
    }
}

要与ObjectMapper一起使用,您可以在实例上注册模块:

ObjectMapper objectMapper = new ObjectMapper();
objectMapper.registerModule(new DefaultStringModule());

要处理JSON中不存在的字段的默认值,我通常会通过使用构建器类来完成此操作,该构建器类将使用提供的值构造类,并为缺少的字段添加任何默认值。然后,在反序列化的类(例如MyClass)上,添加@JsonDeserialize(builder = MyClass.Builder.class)注释以指示Jackson通过构建器类反序列化MyClass