【问题标题】:Jackson ObjectMapper - How to exclude field when value is false after de-serialized from remote response?Jackson ObjectMapper - 如何在从远程响应反序列化后值为假时排除字段?
【发布时间】:2021-08-31 16:50:34
【问题描述】:

我正在远程调用外部服务 A,它会将响应作为 json 返回,然后使用对象映射器反序列化为 MyResponse 对象。之后,在我当前的服务中,我需要附加这个对象并输出到 UI。

来自服务 A 的 MyResponse 中的一个字段是布尔值,我只希望我的 UI 响应在值为 true 时包含此字段。 请注意,我无权修改我的 MyResponse 对象,因为它是只读的。所以我创建了一个 MixIn 类,也尝试了几种方法,但都没有成功..

    public class MyResponse {

        private String stringValue;
        private int intValue;
        // Expectation: only include this field when value true, and exclude it when value is false
        private boolean booleanValue;
    }

    // @JsonIgnoreProperties(value = { "booleanValue" })
    // @JsonSerialize(include = JsonSerialize.Inclusion.NON_EMPTY)
    private static class MixInMyResponse {

    }

    // this would be my rest service eventually send myResponse to UI
    public MyResponse readFromRemote() throws IOException {
        String jsonAsString =
            "{\"stringValue\":\"a\",\"intValue\":1,\"booleanValue\":false}";
        ObjectMapper mapper = new ObjectMapper();
        // configure object mapper with mix in
        mapper.getDeserializationConfig().addMixInAnnotations(MyResponse.class, MixInMyResponse.class);
        MyResponse myResponse = mapper.readValue(jsonAsString, MyResponse.class);
        // Expectation: writeValue needs only include booleanValue when value true, and exclude booleanValue when value is false
        String writeValue = mapper.writeValueAsString(myResponse);
        System.out.println(writeValue);
        return myResponse;
    }

  1. 使用 @JsonIgnoreProperties(value = { "booleanValue" }):当值为 false 时,这会解决问题,但当值为 true 时,它​​也不包含字段
  2. 使用 @JsonSerialize(include = JsonSerialize.Inclusion.NON_EMPTY):当值为false时,这会将字段booleanValue反序列化为false,因此我返回的myResponse/writeValue仍将具有此字段到UI。

对此有什么补充建议吗?

【问题讨论】:

  • 你看过这个Stackoverflow solution
  • @Chabo,是的,我尝试过这种方式,但没有运气,不确定是不是因为我正在使用 MixIn,因为我无法在原始类上修改...

标签: java jackson deserialization objectmapper


【解决方案1】:

编写你自己的序列化器

public class MyResponseSerializer extends JsonSerializer<MyResponse> {
    @Override
    public void serialize(MyResponse myResponse, JsonGenerator jsonGenerator, SerializerProvider serializerProvider) throws IOException, JsonProcessingException {
        jsonGenerator.writeStartObject();
        jsonGenerator.writeStringField("stringValue", myResponse.getStringValue());
        jsonGenerator.writeNumberField("intValue", myResponse.getIntValue());
        if (myResponse.isBooleanValue()) {
            jsonGenerator.writeBooleanField("booleanValue", myResponse.isBooleanValue());
        }
        jsonGenerator.writeEndObject();
    }
}

用 ObjectMapper 注册它

@Test
public void test3() throws IOException {
    MyResponse response1 = new MyResponse("response1", 1, true);
    MyResponse response2 = new MyResponse("response2", 1, false);

    ObjectMapper objectMapper = new ObjectMapper();
    SimpleModule module = new SimpleModule();
    module.addSerializer(MyResponse.class, new MyResponseSerializer());
    objectMapper.registerModule(module);
    System.out.println(objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(response1));
    System.out.println(objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(response2));
}

看到这个tutorial

当我看到您无法修改 MyResponse 以添加注释时,我编辑了原始答案。

【讨论】:

  • 您好,这种方法在writeValueAsString 时有效,我可以在customSerializer 中进行调试,看到我的booleanValue 在写入过程中被忽略/包含。但是,在我的rest api中,我仍然可以看到我的最终输出包含booleanValue,并且我没有看到我的customSerializer断点被击中..这是否意味着我在这里注册的objectMapper没有在我的rest api中使用最终序列化?
  • 我想通了,我其实应该自定义反序列化而不是序列化
【解决方案2】:

你当然可以这样做。

首先,您的booleanValue 字段应该是盒装类型Boolean 而不是前置类型boolean。因为原始类型boolean默认值为false。

您可以为booleanValue 创建一个setter 方法并使用@JsonProperty("booleanValue") 对其进行注释,如下所示。

public class MyResponse {
    private String stringValue;
    private int intValue;
    private Boolean booleanValue;

    @JsonProperty("booleanValue")
    public void anyNameYouWant(Boolean b) {
        if(b) this.booleanValue = true;
    }
    
    // getters and setters
}

最后你可以做到以下几点,

String s = "{\"stringValue\":\"a\",\"intValue\":1,\"booleanValue\":false}";
ObjectMapper om = new ObjectMapper();
om.readValue(s, MyResponse.class);

【讨论】:

  • 谢谢!这也是个好建议,不幸的是我无法修改 MyResponse 课程内容,所以我必须从 外部 进行修改
猜你喜欢
  • 1970-01-01
  • 2017-04-27
  • 2016-12-29
  • 1970-01-01
  • 2011-10-13
  • 2015-06-26
  • 1970-01-01
  • 1970-01-01
  • 2016-12-24
相关资源
最近更新 更多