Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/303.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 使用Jackson反序列化JSON时的隐式默认值_Java_Json_Jackson_Deserialization - Fatal编程技术网

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

Java 使用Jackson反序列化JSON时的隐式默认值,java,json,jackson,deserialization,Java,Json,Jackson,Deserialization,当反序列化各种JSON消息时,我想为特定类型的属性提供一个默认值。只需在类中指定值,但如果必须跨多个类执行此操作,则很容易出错。您可能会忘记一个,结果是null而不是默认值。我的意图是将可选的每个属性设置为可选。缺少。由于null正是Optional试图消除的,因此与Jackson一起使用它们被证明是令人沮丧的 Jackson的大多数特性允许您自定义反序列化过程,它们关注的是作为输入的JSON,而不是实例化要反序列化的对象的过程。我似乎最接近通用解决方案的方法是构建自己的ValueInstant

当反序列化各种JSON消息时,我想为特定类型的属性提供一个默认值。只需在类中指定值,但如果必须跨多个类执行此操作,则很容易出错。您可能会忘记一个,结果是
null
而不是默认值。我的意图是将
可选的每个属性设置为
可选。缺少
。由于
null
正是
Optional
试图消除的,因此与Jackson一起使用它们被证明是令人沮丧的

Jackson的大多数特性允许您自定义反序列化过程,它们关注的是作为输入的JSON,而不是实例化要反序列化的对象的过程。我似乎最接近通用解决方案的方法是构建自己的
ValueInstantiator
,但我还有两个问题:

  • 如何使其仅实例化
    可选
    缺席
    ,而不干扰实例化过程的其余部分
  • 如何将最终结果连接到我的
    ObjectMapper
更新:我想澄清一下,我正在寻找一种解决方案,它不涉及修改包含
可选
的每个类。我反对违反干燥原则。我或我的同事不应该在每次向新的或现有的类添加
可选的
时都考虑必须做一些额外的事情。我想说,“让我反序列化到的每个类中的每个可选字段都预先填充
缺席
”,只做一次,然后完成它

这意味着以下内容已过时:

  • 抽象父类(需要声明)
  • 自定义生成器/创建者/JsonDeserializer(需要对每个适用类进行注释)
  • 米辛的?我尝试了这个,结合了反思,但我不知道如何访问我正在混入的类

您可以编写自定义反序列化程序来处理默认值。实际上,您将针对正在反序列化的对象类型扩展适当的反序列化程序,获取反序列化的值,如果该值为
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);
        }
    }
}

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

专门针对java.lang。可选的,Jackson自己有一个模块:

番石榴可选包含在

它将为null创建一个可选的.emission,但不为缺少的JSON值创建:-(

见和

所以你必须像初始化集合一样初始化你的选项。这是一个很好的实践,所以你应该能够执行它

private Optional<Xxx> xxx = Optional.absent();
private List<Yyy> yyys = Lists.newArrayList();
private Optional xxx=Optional.缺席();
私有列表yyys=Lists.newArrayList();

您的值对象应该将这些值初始化为不存在。这是确保默认值没有空值的方法。对于更高版本,Guava模块的
可选处理程序实际上应该只将它们反序列化为“不存在”(即使是显式JSON空值),而不将它们反序列化为空值。

但由于Jackson只对存在的JSON属性(而不是可能存在但不存在的东西)进行操作,POJO仍然需要有默认的缺席赋值。

问题在于
反序列化()如果属性不在JSON中,则不调用
。我希望这些属性映射到
可选。也不存在
。很抱歉,错过了这一部分。我在回答的末尾添加了一段,以说明我这样做的一种方法。更好的方法是,但是我仍然必须对每个具有可选属性的类进行注释。我希望它是透明的。请参阅@greyfairer关于如何更好地支持可选数据的反序列化/序列化的回答。不幸的是,jackson数据类型guava与您的第一个示例有相同的问题-它只将显式
null
映射到
缺失的
。缺失的值保留为
null
。困惑吗?:)不,我使用的是后一个,它将不存在null值。我不认为这对本地人来说是不一样的,但我可以检查一下。是的,同样的问题。不存在缺省值的骰子:(实际上,番石榴<代码>可选< /COD>反序列化器确实应该将JSON <代码> null <代码>作为“缺省”,使用最新版本。至少使用2.5.3。但是序列化是另一回事,缺省值被认为是“空当量”。因此,根据默认包含,它们可能会被剥离。但是JSON中的属性没有任何值(Jackson没有做任何事情)和显式JSON null之间是有区别的。@LászlóvandenHoek不幸的是,Jackson没有办法做到这一点。啊。实际上,我正要提到这一点,可能是通过
ValueInstantiator
…-)--是的,这是最有可能到达那里的路线。如果可能,最好通过邮件列表进行讨论。但是,是的,应该可以只处理实例化,让实际的反序列化继续进行。您有没有找到将可选值保留为空而不是空的解决方案。@Araf现在可能会处理它?我还没有检查,请检查并在这里报告:)
private Optional<Xxx> xxx = Optional.absent();
private List<Yyy> yyys = Lists.newArrayList();