当缺少字段时,将 Jackson 与 Optional 一起使用以生成 Optional.empty()

Using Jackson with Optional to generate Optional.empty() when field is missing

提问人:harsh pamnani 提问时间:11/11/2023 更新时间:11/11/2023 访问量:62

问:

我正在使用 Jackson 将 json 字符串转换为 java 对象。我的类中有一个可选字段。 每当我尝试反序列化缺少可选字段的字符串时,它都会为该字段而不是 生成。nullOptional.empty()

代码如下:

public class Main {
    public static void main(String[] args) throws JsonProcessingException {
        ObjectMapper mapper = new ObjectMapper();
        mapper.registerModule(new Jdk8Module());
        Person1 p1 = mapper.readValue("{\"name\": \"harsh\"}", Person1.class);
        System.out.println(p1);
    }
}
@EqualsAndHashCode
@ToString
@Getter
@Builder
@NoArgsConstructor(force = true)
public class Person1 {
    public final String name;
    public final Optional<Integer> age;

    public Person1(String name, Optional<Integer> age) {
        this.name = name;
        this.age = age;
    }
}

它生成以下输出:

Person1(name=harsh, age=null)

但是,我希望它生成:

Person1(name=harsh, age=Optional.empty)

我还尝试添加客户反序列化程序,如下所示,但它似乎不起作用:OptionalIntegerDeserializer

public class Person1 {
    public final String name;
    @JsonDeserialize(using = OptionalIntegerDeserializer.class)
    public final Optional<Integer> age;

    public Person1(String name, Optional<Integer> age) {
        this.name = name;
        this.age = age;
    }

    public static class OptionalIntegerDeserializer extends StdDeserializer<Optional<Integer>> {
        public OptionalIntegerDeserializer() {
            super(Optional.class);
        }

        @Override
        public Optional<Integer> deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
            JsonNode node = p.readValueAsTree();
            if (node.isNull()) {
                return Optional.empty();
            } else {
                return Optional.of(node.intValue());
            }
        }
    }
}

有没有办法生成而不是缺失的字段?Optional.emptynull

java jackson jackson-databind

评论


答:

1赞 Ahmed Mera 11/11/2023 #1

解决方案是

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@JsonIgnoreProperties(ignoreUnknown = true)
public class Person {
    
    private String name;
    
    @JsonDeserialize(using = OptinalDeserializer.class)
    @Builder.Default
    private Optional<Integer> age = Optional.empty();
}

自定义反序列化是

public class OptionalIntegerDeserializer extends StdDeserializer<Optional<Integer>> {

    protected OptionalIntegerDeserializer() {
        super(Optional.class);
    }

    @Override
    public Optional<Integer> deserialize(JsonParser parser, DeserializationContext context) {
        if (parser.getValueAsInt() > 0 ) {
            return Optional.of(parser.getValueAsInt());
        } else {
            return Optional.empty();
        }
    }
}

第一次测试

 public static void main(String[] args) throws JsonProcessingException {
    String s = "{\"name\": \"harsh\"}";
    Person p = JsonMapper.builder().build().readValue(s, Person.class);

    System.out.println(p);
 }

输出 1 为:Person(name=harsh, age=Optional.empty)

第二次测试

 public static void main(String[] args) throws JsonProcessingException {
    String s = "{\"name\": \"harsh\", \"age\": 19}";
    Person p = JsonMapper.builder().build().readValue(s, Person.class);

    System.out.println(p);
 }

输出 2 为:Person(name=harsh, age=Optional[19])

我试过了,它有效,你能试试吗,让我知道它是否有效。

评论

1赞 harsh pamnani 11/12/2023
了不起。谢谢。它现在使用默认值工作。
1赞 harsh pamnani 11/12/2023
为可选字段添加默认值后,似乎我们甚至不需要自定义反序列化程序。没有它也能正常工作。OptionalIntegerDeserializer
1赞 Ahmed Mera 11/13/2023
我让自定义反序列化程序,因为如果你想在反序列化过程中执行另一个逻辑。
0赞 harsh pamnani 11/13/2023
棒。谢谢。