Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/303.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 自定义Jackson HttpMessageConverter在Spring 4.2中不再工作_Java_Json_Spring Mvc_Jackson - Fatal编程技术网

Java 自定义Jackson HttpMessageConverter在Spring 4.2中不再工作

Java 自定义Jackson HttpMessageConverter在Spring 4.2中不再工作,java,json,spring-mvc,jackson,Java,Json,Spring Mvc,Jackson,我正在将一个应用程序从Spring平台版本1.1.3.RELEASE升级到2.0.1.RELEASE,这将Spring框架版本从4.1.7升级到4.2.4,将Jackson从2.4.6升级到2.6.4。Spring或Jackson对自定义HttpMessageConverter实现的处理似乎没有任何重大变化,但我的自定义JSON序列化失败了,我无法确定原因。在上一个Spring Platform版本中,以下功能可以正常工作: 型号 @JsonFilter("fieldFilter") publi

我正在将一个应用程序从Spring平台版本1.1.3.RELEASE升级到2.0.1.RELEASE,这将Spring框架版本从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);
    }
}
配置

@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
}
执行
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());
            }
        }
    }
    
    @Autowired-WebApplicationContext-WebApplicationContext;
    @以前
    公共作废设置(){
    mockMvc=MockMvcBuilders.webAppContextSetup(webApplicationContext.build();
    }
    @试验
    public void test()引发异常{
    RequestMappingHandlerAdapter=(RequestMappingHandlerAdapter)webApplicationContext.getBean(“RequestMappingHandlerAdapter”);
    List genes=EntrezGene.createDummyData();
    Set exclude=new HashSet();
    排除。添加(“entrezGeneId”);
    ResponseEnvelope=新ResponseEnvelope(基因,新HashSet(),排除);
    对于(HttpMessageConverter:adapter.getMessageConverters()){
    System.out.println(converter.getClass().getName());
    if(converter.canWrite(responseenevelope.class,MediaType.APPLICATION_JSON)){
    MockHttpOutputMessage=新的MockHttpOutputMessage();
    write((对象)信封,MediaType.APPLICATION_JSON,message);
    System.out.println(message.getBodyAsString());
    }
    }
    }
    

    …而且效果很好。我的
    信封
    对象及其内容已正确序列化和筛选。因此,在请求到达消息转换器之前,它的处理存在问题,或者,
    MockMvc
    测试请求的方式发生了变化。

    您的配置正常。未从自定义转换器调用
    writeInternal()
    的原因是重写了错误的方法

    查看
    4.2.4.发行版的源代码

    抽象消息转换器方法处理器#编写消息转换器

    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#write(…)
    中调用的方法
    writeInternal(…)
    有三个参数-
    (T,Type Type,HttpOutputMessage outputMessage)
    。您正在重写重载版本的
    writeInternal(…)
    ,该版本只有两个参数-
    (T,HttpOutputMessage outputMessage)

    但是,在版本
    4.1.7.RELEASE
    中,情况并非如此,因此是问题的根本原因。此版本中使用的
    writeInternal(…)
    是您已重写的另一个重载方法(具有2个参数的方法)。这解释了为什么它在
    4.1.7.RELEASE
    中运行良好

    @Override
    public final void write(final T t, MediaType contentType, HttpOutputMessage outputMessage)
                throws IOException, HttpMessageNotWritableException {
        ...
        writeInternal(t, outputMessage);
        ...
    }
    

    因此,要解决您的问题,请不要重写
    writeInternal(对象对象,HttpOutputMessage outputMessage)
    ,而要重写
    writeInternal(对象对象,类型,HttpOutputMessage outputMessage)

    configureMessageConverters
    中放置一个断点,并确保它正在执行。@chrylis:已经尝试过了,配置方法正在执行。您能提供完整的stacktrace吗?@frant.hartm:我在日志中添加了完整的错误消息。Spring容器捕获异常并生成一个500错误的响应。@woemler您是否已将方法
    setFilters(filters)
    更改为
    setFilterProvider(filters)
    ?以前没有。与
    setFilters()
    不同,
    setFilterProvider()
    返回
    ObjectMapper
    ,因此您不应该执行
    ObjectMapper.setFilterProvider(filters).writeValue(jsonGenerator,object)?成功了!非常感谢你!令人费解的是,为什么他们决定更改此方法的功能,但至少我现在对引擎盖下发生的事情有了更好的了解。诀窍是将Spring logs设置为ALL,以获得有关内部发生情况的精彩故事:)
    
    protected <T> void writeWithMessageConverters(T returnValue, MethodParameter returnType,
                ServletServerHttpRequest inputMessage, ServletServerHttpResponse outputMessage)
                throws IOException, HttpMediaTypeNotAcceptableException, HttpMessageNotWritableException {
        ...
        ((GenericHttpMessageConverter<T>) messageConverter).write(returnValue, returnValueType, selectedMediaType, outputMessage);
        ...
    }
    
    public final void write(final T t, final Type type, MediaType contentType, HttpOutputMessage outputMessage)
                throws IOException, HttpMessageNotWritableException {
        ...
        writeInternal(t, type, outputMessage);
        ...
    }
    
    @Override
    public final void write(final T t, MediaType contentType, HttpOutputMessage outputMessage)
                throws IOException, HttpMessageNotWritableException {
        ...
        writeInternal(t, outputMessage);
        ...
    }