由@EnableWebMvc注解引发的Jackson解析异常

同事合了代码到开发分支,并没有涉及到改动的类却报错。错误信息如下:

Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; 
nested exception is org.springframework.http.converter.HttpMessageConversionException: 
Type definition error: [simple type, class com.tongweb.demo.bean.Registration];
nested exception is com.fasterxml.jackson.databind.exc.InvalidDefinitionException:
Cannot construct instance of `com.tongweb.demo.bean.Registration` (no Creators, like default constructor, exist): cannot deserialize from Object value (no delegate- or property-based Creator)

这个错误的大概意思就是jackson解析Registration类时出现了错误,说Registration类缺少默认构造函数。这个类是Controller中一个方法的入参。示例代码如下:

@PostMapping(path = "/instances", consumes = MediaType.APPLICATION_JSON_VALUE)  
public String register(@RequestBody Registration registration) {  
    Registration withSource = Registration.copyOf(registration).source("http-api").build(); 
    return withSource.toString();  
}

相关代码并不涉及到改动,自从我同事代码合过来就开始报错,很不应该。起初我猜测是某些jar冲突引起的。但是查看了他合并过来的代码,也并未涉及到jar依赖的升级变更等。对于这个错误网上是有很多解决方案的,比如加个构造函数。但是不排查到导致问题的原因,这总归是个雷。于是我开启了漫长的排除过程。

首先考虑是jar冲突导致。我重新写了一个新项目,沿用了我目前的所有jar。访问instances接口,jackson解析并不会报错。那只有跟踪源码了。

spring提供了一个Jackson的HTTP消息转换器的配置JacksonHttpMessageConvertersConfiguration,会创建一个MappingJackson2HttpMessageConverterMappingJackson2HttpMessageConverter会负责解析Registration类。特别说明Registration类只有有参构造函数,没有无参构造函数。

HttpMessageConverters负责管理Spring Boot应用程序中使用的HttpMessageConverters。提供了一种向web应用程序添加和合并其他HttpMessageConverter的方便方法。
如果需要,可以向特定的附加转换器注册此bean的实例,否则将使用默认转换器。说白了就是Spring Boot应用程序中的各个转换就是在HttpMessageConverters中。

按理来说MappingJackson2HttpMessageConverter也是HttpMessageConverters中的一员。但是我跟踪源码发现MappingJackson2HttpMessageConverter并未出现在HttpMessageConverters中。跟踪源码WebMvcConfigurationSupport类,源码如下:


protected final void addDefaultHttpMessageConverters(List<HttpMessageConverter<?>> messageConverters) {  
    messageConverters.add(new ByteArrayHttpMessageConverter());  
    messageConverters.add(new StringHttpMessageConverter());  
    messageConverters.add(new ResourceHttpMessageConverter());  
    messageConverters.add(new ResourceRegionHttpMessageConverter());
    ...
}

这一段关键代码是把HttpMessageConverters添加到messageConverters。后续解析@RequestBody修饰的类就会从中选择对应的Converter。当源码进行到这一步的时候。我发现MappingJackson2HttpMessageConverter并不存在。

为什么JacksonHttpMessageConvertersConfiguration没有被加载呢。答案就是@EnableWebMvc注解!!

@EnableWebMvc注解的作用是导入DelegatingWebMvcConfiguration类,这个类是一个@Configuration类,它会创建一个WebMvcConfigurationSupport类的实例,并将其注册到容器中。WebMvcConfigurationSupport类是Spring MVC的核心配置类,它会提供一些默认的组件,包括一些默认的HttpMessageConverter。但是,这些默认的转换器中并不包含MappingJackson2HttpMessageConverter,因为它需要依赖Jackson库,而Spring MVC并不强制依赖Jackson库。

Spring Boot的WebMvcAutoConfiguration类是一个@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)的类,它会在容器中没有WebMvcConfigurationSupport类的实例的时候才会被加载。这个类会提供一些自动配置的组件,包括MappingJackson2HttpMessageConverter。它会检测容器中是否有Jackson库,如果有的话,就会创建一个MappingJackson2HttpMessageConverter对象,并将其添加到HttpMessageConverters对象中。

当我们在应用程序中使用@EnableWebMvc注解时,就会导致容器中有一个WebMvcConfigurationSupport类的实例,这样就会触发@ConditionalOnMissingBean(WebMvcConfigurationSupport.class)的条件,使得WebMvcAutoConfiguration类不会被加载。这样,MappingJackson2HttpMessageConverter就不会被创建,也不会被添加到HttpMessageConverters对象中。因此,@EnableWebMvc注解就导致MappingJackson2HttpMessageConverter没有被装配了。

这样的话,Spring Boot的默认MVC配置就会被关闭,你需要自己配置Spring MVC的功能,例如拦截器、视图解析器、消息转换器等。

最后附录一下导致问题发生的代码:

在这里插入图片描述

  • 7
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

文安初心忆往昔

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值