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

Lás*_*oek 6 java json jackson deserialization

在反序列化各种JSON消息时,我想为某种类型的属性提供默认值.它通常建议简单地指定的类值,但是如果你要在许多类做到这一点,这是容易出错.您可能会忘记一个并最终得到null而不是默认值.我的目的是设置每个属性Optional<T>Optional.absent.由于null正是Optional试图消除的,因此将它们与杰克逊一起使用已被证明是令人沮丧的.

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

  • 我怎么让它只实例Optionalabsent,但不与实例化过程的其余部分干扰?
  • 如何将最终结果连接到我的ObjectMapper

更新:我想澄清我正在寻找一个涉及修改包含的每个类的解决方案Optional.我反对违反DRY原则.每次我们添加Optional新的或现有的课程时,我或我的同事都不应该考虑做额外的事情.我希望能够说,"让每个Class中的每个可选字段反序列化,预填充Absent",只需一次,并完成它.

这意味着以下内容:

  • 抽象父类(需要声明)
  • 自定义Builder/Creator/JsonDeserializer(需要在每个适用的类上进行注释)
  • 混入的?我尝试了这个,结合反射,但我不知道如何访问我被混入的类...

Eri*_*pie 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);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

要使用它,ObjectMapper您可以在实例上注册该模块:

ObjectMapper objectMapper = new ObjectMapper();
objectMapper.registerModule(new DefaultStringModule());
Run Code Online (Sandbox Code Playgroud)

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