java - 是否可以为一个特定的执行配置 ObjectMapper?
问题描述
我正在开发一个 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
创建-instance。ObjectWriter
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
您在评论中所说,您还可以使用该方法ObjectMapper
基于全局实例创建一个临时的新实例。ObjectMapper#copy()
想法是一样的:使用全局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);
}