java – 自定义的Jackson HttpMessageConverter不再适用于Spring
我正在从
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处理自定义HttpMessageConverter实现方面似乎没有任何重大变化,但是我的自定义
JSON序列化未能发生,我无法确定为什么.在以前的Spring Platform版本中,以下工作正常:
模型 @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()); } } } …它工作正常.我的信封对象及其内容被序列化并被正确过滤.因此,在到达消息转换器之前,请求处理有问题,或者MockMvc如何测试请求发生了变化. 解决方法
你的配置没问题没有从您的自定义转换器调用writeInternal()的原因是因为您覆盖了错误的方法.
看看4.2.4.RELEASE的源代码 AbstractMessageConverterMethodProcessor#writeWithMessageConverters protected <T> void writeWithMessageConverters(T returnValue,MethodParameter returnType,ServletServerHttpRequest inputMessage,ServletServerHttpResponse outputMessage) throws IOException,HttpMediaTypeNotAcceptableException,HttpMessageNotWritableException { ... ((GenericHttpMessageConverter<T>) messageConverter).write(returnValue,returnValueType,selectedMediaType,outputMessage); ... } AbstractGenericHttpMessageConverter#写 public final void write(final T t,final Type type,MediaType contentType,HttpMessageNotWritableException { ... writeInternal(t,type,outputMessage); ... } 从AbstractGenericHttpMessageConverter#write(…)中调用的writeInternal(…)方法有三个参数 – (T t,Type type,HttpOutputMessage outputMessage).您将覆盖只有2个参数的writeInternal(…)的重载版本(T t,HttpOutputMessage outputMessage). 但是,在版本4.1.7.RELEASE中,情况并非如此,因此是您问题的根本原因.在这个版本中使用的writeInternal(…)是另一个重载的方法(有2个参数的方法),你已经被覆盖了.这解释了为什么它在4.1.7.RELEASE中正常工作. @Override public final void write(final T t,outputMessage); ... } 所以,为了解决你的问题,而不是覆盖writeInternal(Object对象,HttpOutputMessage outputMessage),重写writeInternal(Object对象,Type类型,HttpOutputMessage outputMessage) (编辑:李大同) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |