【问题标题】:Is it possible to configure ObjectMapper for one specific execution?是否可以为一个特定的执行配置 ObjectMapper?
【发布时间】:2021-02-27 13:21:08
【问题描述】:

我正在开发一个 Web 项目,它使用一个静态 ObjectMapper,它是通过 XML 文件配置的,并且应该在整个项目中生效。但是,无论设置如何,我都必须实现一个 API 来发送一个不忽略 null 属性的响应。我的老板告诉我他不希望创建另一个 ObjectMapper,并且创建我自己的 JSON 编写器被认为是多余的,因此也被禁止。这导致我被困在这里。 我试过了。

        Map<String, Object>resultMap = getResult();
        try {
            mapper.setSerializationInclusion(Include.ALWAYS);
            response = mapper.writeValueAsString(resultMap);
        } catch (JsonProcessingException e) {
            throw new RuntimeException(e);
        } finally {
            if (ServiceConfig.isWriteNull()) {
                mapper.setSerializationInclusion(Include.ALWAYS);
            } else {
                mapper.setSerializationInclusion(Include.NON_NULL);
            }
        }

要临时切换设置,它可以工作。但是考虑到映射器是异步使用的,改变全局配置绝对是个坏主意。我也想过在配置切换之前给映射器加个锁,但是由于映射器是静态的,这可能是另一个坏主意。我想有一些巧妙的方法,比如注释或参数神奇地影响单个执行。不知道有没有可能?

【问题讨论】:

  • 你不能有两个不同的ObjectMapper 实例吗?
  • 根据性能,您还应该能够复制 ObjectMapper stackoverflow.com/a/61614730/5126654 即复制映射器,然后更改配置。

标签: java json objectmapper fasterxml


【解决方案1】:
    Map<String, Object>resultMap = getResult();
         try {
            response = mapper
                .writer(SerializationFeature.WRITE_NULL_MAP_VALUES)
                .writeValueAsString(resultMap);
         } catch (JsonProcessingException e) { throw new RuntimeException(e);}

【讨论】:

    【解决方案2】:

    您目前拥有的是危险的,因为您正在临时更改全局映射器的配置。这也会影响同时使用同一个映射器实例进行序列化的其他线程。

    但是,还有另一种方法可以满足您的需求。 ObjectMapper 实例有几种方法可以根据您的映射器创建ObjectWriter-instance。

    Map<String, Object> resultMap = getResult();
    try {
        response = mapper
            .writer(SerializationFeature.WRITE_NULL_MAP_VALUES)
            .writeValueAsString(resultMap);
    } catch (JsonProcessingException e) {
        throw new RuntimeException(e);
    }
    

    正如@Stepan Stahlmann 在您的cmets 中所说,您还可以使用ObjectMapper#copy() 方法基于全局实例创建一个临时的新ObjectMapper 实例。想法是一样的:使用全局 ObjectMapper 作为配置的根并进行一些调整,使其生成适合 API-Contract 的 JSON。

    Map<String, Object> resultMap = getResult();
    try {
        response = mapper
            .copy()
            .setSerializationInclusion(Include.ALWAYS)
            .writeValueAsString(resultMap);
    } catch (JsonProcessingException e) {
        throw new RuntimeException(e);
    }
    

    另一种方法...

    还有另一种我能想到的方法,我敢肯定还有更多。 您可以将 resultMap 包装在一个带有一些注释的类中,这些注释应该推翻映射器的默认行为:

    package example;
    
    import com.fasterxml.jackson.annotation.JsonInclude;
    import com.fasterxml.jackson.annotation.JsonValue;
    
    import java.util.Map;
    
    // Your inclusion rule
    @JsonInclude(JsonInclude.Include.ALWAYS)
    public class ResponseWrapper {
    
        private final Map<String, Object> response;
    
        public ResponseWrapper(Map<String, Object> response) {
            this.response = response;
        }
    
        // tells Jackson to use the this a the actual value (so you don't see this wrapper in the json)
        @JsonValue
        public Map<String, Object> getResponse() {
            return this.response;
        }
    }
    
    
    Map<String, Object> resultMap = getResult();
    try {
        response = mapper.writeValueAsString(new ResponseWrapper(resultMap));
    } catch (JsonProcessingException e) {
        throw new RuntimeException(e);
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2021-08-14
      • 1970-01-01
      • 2021-06-09
      • 1970-01-01
      • 1970-01-01
      • 2011-03-17
      • 2015-05-03
      • 1970-01-01
      相关资源
      最近更新 更多