【问题标题】:How can I configure a Jackson ObjectMapper to serialize certain fields of certain beans with a custom value if they are null?如果它们为空,如何配置 Jackson ObjectMapper 以使用自定义值序列化某些 bean 的某些字段?
【发布时间】:2017-01-11 13:31:52
【问题描述】:

我有一个属于我无权访问的第三方库的类。它看起来像:

public class Product {

    private String thumbnailUrl;    

   // many other properties, some of which are POJOs or collections

    public String getThumbnailUrl() {
        return thumbnailUrl;
    }

    public void setThumbnailUrl(String thumbnailUrl) {
        this.thumbnailUrl = thumbnailUrl;
    }
}

这只是我将使用 Jackson 序列化为字符串的类之一。还有很多其他的。

thumbnailUrl 属性有时可以是 null。如果是null,如何配置ObjectMapper 将此字段序列化为http://www.example.com/unknown.png

我认为我不能使用 mixins,因为 mixins 无法访问原始对象,因此他们无法检查属性的值是否为 null

【问题讨论】:

    标签: java json jackson


    【解决方案1】:

    这应该可以解决问题:

    private String thumbnailUrl = "http://my.default.url";

    由于cmets中提到的OP,该类来自第三方库,因此修改它(a'la this SO)或注释(a'la this SO)不是一种选择。在这种情况下,您有两个选择:

    • 为第三方库打补丁(显然你可以访问源代码;))

    • 在自定义序列化程序中破解它(但需要经过适当测试,这种快速破解在多线程环境中不起作用)

    如:

    @Override
    public void serialize(Product value, JsonGenerator jgen, SerializerProvider provider) 
      throws IOException, JsonProcessingException {
        boolean revert = false;
        if (value.thumbnailUrl == null) {
          value.thumbnailUrl = "http://my.default.url";
          revert = true;
        }
        jgen.writeObject(value);
        if (revert) {
          value.thumbnailUrl = null;
        }
    }
    

    【讨论】:

    • 如问题中所述,这是第三方类,我无权访问源代码。我想把这个逻辑外化。
    • 那么恐怕你必须为这个类编写自己的序列化程序。有很多方法,例如,baeldung.com/jackson-custom-serialization 当然你不能注释类,但仍然可以配置你的 ObjectMapper 为类使用你的自定义序列化程序(也在链接的方法中)
    • 我可以编写自定义序列化程序,但我希望序列化的所有方面都保持原样,并且只自定义该字段的序列化。如果我为具有 20 个字段的 POJO 编写自定义序列化程序并为所有 20 个字段添加序列化逻辑,那就太糟糕了。
    • 是的,但你可以破解它,我会更新我的答案,请给我几分钟。
    • 这在我的情况下不起作用,因为更改 thumbnail 属性的值会产生不必要的副作用(例如,听众被触发等)我将这个答案标记为已接受(直到有人来找到更好的解决方案)。
    【解决方案2】:

    我最终得到了这个解决方案,但它并不像我期望的那么简单:

    @Test
    public void shouldSerializeDefaultThumbnailUrlIfThumbnailUrlIsNull() throws Exception {
        // Given
        Product p = new Product();
        p.setPrimaryKey("123");
    
        PropertyFilter filter = new SimpleBeanPropertyFilter() {
            @Override
            public void serializeAsField(Object pojo, JsonGenerator jgen, SerializerProvider prov, PropertyWriter writer) throws Exception {
                if (pojo.getClass().equals(Product.class)
                        && ((Product) pojo).getThumbnailUrl() == null
                        && writer.getName().equals("thumbnailUrl")) {
                    jgen.writeStringField(writer.getName(), "http://www.example.com/default.png");
                } else {
                    writer.serializeAsField(pojo, jgen, prov);
                }
            }
        };
    
        FilterProvider filters = new SimpleFilterProvider().addFilter("thumbnailFilter", filter);
    
        this.mapper.setFilterProvider(filters);
        String json = this.mapper.writeValueAsString(p);
    
        assertThat(json, equalTo("{\"thumbnailUrl\":\"http://www.example.com/default.png\",\"id\":\"123\"}"));
    }
    

    忽略这个。它在我的情况下不起作用,因为我的课程需要注释,而我不能。

    【讨论】:

    • 如果我可以为Product 类实现一个com.fasterxml.jackson.databind.JsonSerializer,该类与默认序列化程序相同,但仅针对该特定字段具有此规则,那就更好了。
    • 那确实不错,但我还没有找到一个很好、简单的方法来做到这一点。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-16
    • 2013-11-15
    • 2017-04-07
    • 1970-01-01
    相关资源
    最近更新 更多