自定义 Jackson HttpMessageConverter 在 Spring 4.2 中不再有效
我正在将Spring Platform版本1.1.3.RELEASE更新到2.0.1.RELEASE,它将Spring Framework版本从4.1.7升级到4.2.4,Jackson从2.4.6升级到2.6.4。在Spring或Jackson对自定义实现的处理中似乎没有任何重大变化,但我的自定义JSON序列化未能发生,我无法确定原因。以下内容在以前的Spring Platform版本中工作正常:HttpMessageConverter
型
@JsonFilter("fieldFilter")
public class MyModel {
/*model fields and methods*/
}
模型包装器
public class ResponseEnvelope {
private Set<String> fieldSet;
private Set<String> exclude;
private Object entity;
public ResponseEnvelope(Object entity) {
this.entity = entity;
}
public ResponseEnvelope(Object entity, Set<String> fieldSet, Set<String> exclude) {
this.fieldSet = fieldSet;
this.exclude = exclude;
this.entity = entity;
}
public Object getEntity() {
return entity;
}
@JsonIgnore
public Set<String> getFieldSet() {
return fieldSet;
}
@JsonIgnore
public Set<String> getExclude() {
return exclude;
}
public void setExclude(Set<String> exclude) {
this.exclude = exclude;
}
public void setFieldSet(Set<String> fieldSet) {
this.fieldSet = fieldSet;
}
public void setFields(String fields) {
Set<String> fieldSet = new HashSet<String>();
if (fields != null) {
for (String field : fields.split(",")) {
fieldSet.add(field);
}
}
this.fieldSet = fieldSet;
}
}
控制器
@Controller
public class MyModelController {
@Autowired MyModelRepository myModelRepository;
@RequestMapping(value = "/model", method = RequestMethod.GET, produces = { MediaType.APPLICATION_JSON_VALUE })
public HttpEntity find(@RequestParam(required=false) Set<String> fields, @RequestParam(required=false) Set<String> exclude){
List<MyModel> objects = myModelRepository.findAll();
ResponseEnvelope envelope = new ResponseEnvelope(objects, fields, exclude);
return new ResponseEntity<>(envelope, HttpStatus.OK);
}
}
自定义 HttpMessageConverter
public class FilteringJackson2HttpMessageConverter extends MappingJackson2HttpMessageConverter {
private boolean prefixJson = false;
@Override
public void setPrefixJson(boolean prefixJson) {
this.prefixJson = prefixJson;
super.setPrefixJson(prefixJson);
}
@Override
protected void writeInternal(Object object, HttpOutputMessage outputMessage)
throws IOException, HttpMessageNotWritableException {
ObjectMapper objectMapper = getObjectMapper();
JsonGenerator jsonGenerator = objectMapper.getFactory().createGenerator(outputMessage.getBody());
try {
if (this.prefixJson) {
jsonGenerator.writeRaw(")]}', ");
}
if (object instanceof ResponseEnvelope) {
ResponseEnvelope envelope = (ResponseEnvelope) object;
Object entity = envelope.getEntity();
Set<String> fieldSet = envelope.getFieldSet();
Set<String> exclude = envelope.getExclude();
FilterProvider filters = null;
if (fieldSet != null && !fieldSet.isEmpty()) {
filters = new SimpleFilterProvider()
.addFilter("fieldFilter", SimpleBeanPropertyFilter.filterOutAllExcept(fieldSet))
.setFailOnUnknownId(false);
} else if (exclude != null && !exclude.isEmpty()) {
filters = new SimpleFilterProvider()
.addFilter("fieldFilter", SimpleBeanPropertyFilter.serializeAllExcept(exclude))
.setFailOnUnknownId(false);
} else {
filters = new SimpleFilterProvider()
.addFilter("fieldFilter", SimpleBeanPropertyFilter.serializeAllExcept())
.setFailOnUnknownId(false);
}
objectMapper.setFilterProvider(filters);
objectMapper.writeValue(jsonGenerator, entity);
} else if (object == null){
jsonGenerator.writeNull();
} else {
FilterProvider filters = new SimpleFilterProvider().setFailOnUnknownId(false);
objectMapper.setFilterProvider(filters);
objectMapper.writeValue(jsonGenerator, object);
}
} catch (JsonProcessingException e){
e.printStackTrace();
throw new HttpMessageNotWritableException("Could not write JSON: " + e.getMessage());
}
}
}
配置
@Configuration
@EnableWebMvc
public class WebServicesConfig extends WebMvcConfigurerAdapter {
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
FilteringJackson2HttpMessageConverter jsonConverter = new FilteringJackson2HttpMessageConverter();
jsonConverter.setSupportedMediaTypes(MediaTypes.APPLICATION_JSON);
converters.add(jsonConverter);
}
// Other configurations
}
现在我得到这个异常(被Spring捕获并记录)和500错误,当提出任何类型的请求时:
[main] WARN o.s.w.s.m.s.DefaultHandlerExceptionResolver - Failed to write HTTP message:
org.springframework.http.converter.HttpMessageNotWritableException: Could not write content:
Can not resolve PropertyFilter with id 'fieldFilter';
no FilterProvider configured (through reference chain:
org.oncoblocks.centromere.web.controller.ResponseEnvelope["entity"]->java.util.ArrayList[0]);
nested exception is com.fasterxml.jackson.databind.JsonMappingException:
Can not resolve PropertyFilter with id 'fieldFilter';
no FilterProvider configured (through reference chain:
org.oncoblocks.centromere.web.controller.ResponseEnvelope["entity"]->java.util.ArrayList[0])
该方法执行,但它看起来不像在请求期间使用过自定义转换器。是否有可能另一个消息转换器阻止此消息转换器到达我的响应?我的理解是,覆盖将阻止使用手动注册的转换器以外的转换器。configureMessageConverters
configureMessageConverters
除了通过Spring平台更新依赖项版本外,此代码的工作版本和非工作版本之间没有进行任何更改。JSON 序列化中是否有任何更改,我只是在文档中缺少这些更改?
编辑
进一步的测试会产生奇怪的结果。我想测试以检查以下内容:
- 我的自定义是否实际已注册?
HttpMessageConverter
- 另一个转换器是否覆盖/取代了它?
- 这是否仅与我的测试设置有关?
因此,我添加了一个额外的测试并查看了输出:
@Autowired WebApplicationContext webApplicationContext;
@Before
public void setup(){
mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
}
@Test
public void test() throws Exception {
RequestMappingHandlerAdapter adapter = (RequestMappingHandlerAdapter) webApplicationContext.getBean("requestMappingHandlerAdapter");
List<EntrezGene> genes = EntrezGene.createDummyData();
Set<String> exclude = new HashSet<>();
exclude.add("entrezGeneId");
ResponseEnvelope envelope = new ResponseEnvelope(genes, new HashSet<String>(), exclude);
for (HttpMessageConverter converter: adapter.getMessageConverters()){
System.out.println(converter.getClass().getName());
if (converter.canWrite(ResponseEnvelope.class, MediaType.APPLICATION_JSON)){
MockHttpOutputMessage message = new MockHttpOutputMessage();
converter.write((Object) envelope, MediaType.APPLICATION_JSON, message);
System.out.println(message.getBodyAsString());
}
}
}
...它工作正常。我的对象及其内容已正确序列化和筛选。因此,要么请求处理在到达消息转换器之前存在问题,要么在测试请求的方式上发生了变化。envelope
MockMvc