Spring中MappingJackson2HttpMessageConverter未触发问题排查
我之前维护Spring老项目时也碰到过几乎一模一样的问题,结合你的场景(Spring5、XML配置、自定义JSON转换器),咱们从几个最可能的方向逐一排查:
1. 优先检查HttpMessageConverter的注册顺序
这是最常见的原因!Spring会按照转换器的注册顺序来匹配处理请求,如果你没有禁用默认转换器,默认的MappingJackson2HttpMessageConverter会先于你的自定义转换器被注册。当请求的MediaType(比如application/json-v1)被默认转换器识别为可处理的类型(默认转换器会匹配所有application/json*类型),就会直接用默认转换器处理,你的自定义转换器的writeInternal自然不会被触发。
验证与解决:
- 在XML配置的
<mvc:message-converters>标签里添加register-defaults="false",这样Spring就不会自动注册默认转换器,你需要手动注册所有需要的转换器(包括你的自定义JSON、XML转换器,以及StringHttpMessageConverter这类基础转换器)。 - 确保你的
AppMappingJackson2HttpMessageConverter在转换器列表里排在最前面,示例配置:<mvc:annotation-driven> <mvc:message-converters register-defaults="false"> <!-- 自定义JSON转换器放在最前面 --> <bean class="com.yourpackage.AppMappingJackson2HttpMessageConverter"> <property name="supportedMediaTypes"> <list> <value>application/json-v1</value> </list> </property> </bean> <!-- 自定义XML转换器 --> <bean class="com.yourpackage.AppJaxb2RootElementHttpMessageConverter"> <property name="supportedMediaTypes"> <list> <value>application/xml-v1</value> </list> </property> </bean> <!-- 手动添加基础转换器 --> <bean class="org.springframework.http.converter.StringHttpMessageConverter"/> </mvc:message-converters> </mvc:annotation-driven> - 可以在自定义转换器的构造方法或init方法里打印日志,确认它的注册顺序是否在默认转换器之前。
2. 检查自定义转换器的supports方法实现
虽然你的转换器初始化成功,也能返回JSON,但如果supports(Class<?> clazz)方法返回false,Spring会跳过它,不会调用writeInternal。
验证与解决:
- 在
supports方法里添加日志,输出传入的实体类类型和返回值,比如:@Override protected boolean supports(Class<?> clazz) { boolean result = super.supports(clazz); System.out.println("Supports class " + clazz.getName() + ": " + result); return result; } - 如果发现对控制器返回的实体类返回
false,检查是否在重写supports时错误地修改了逻辑,确保调用super.supports(clazz)或者正确判断实体类类型。
3. 确认MediaType的匹配一致性
要确保你的自定义转换器支持的MediaType和控制器@RequestMapping的produces、请求头的Accept完全匹配:
- 检查XML配置中
supportedMediaTypes的配置,是否精确指定了application/json-v1(包括是否带字符集,比如application/json-v1;charset=UTF-8,如果请求头或produces带字符集,转换器也要对应)。 - 确认控制器的
produces属性是否准确,比如:@RequestMapping(value = "/api/data", produces = "application/json-v1") public ResponseEntity<DataVO> getData() { // ... }
4. 检查是否误重写了write方法而非writeInternal
MappingJackson2HttpMessageConverter的write方法是对外的入口,它会调用writeInternal。如果你不小心重写了write方法但没有调用super.write(),也没有手动调用writeInternal,那么你的自定义转换逻辑就不会执行。
验证:
- 检查你的
AppMappingJackson2HttpMessageConverter是否重写了write方法,如果有,确保里面包含:@Override public void write(Object object, Type type, MediaType contentType, HttpOutputMessage outputMessage) throws IOException, HttpMessageNotWritableException { // 必须调用父类方法,或者手动调用writeInternal super.write(object, type, contentType, outputMessage); }
5. 排查Spring与Jackson版本兼容性
你的项目从Spring3升级到Spring5,要确保Jackson版本和Spring5兼容(Spring5要求Jackson 2.9.x及以上版本)。如果版本不匹配,可能会出现隐藏的方法调用异常,导致writeInternal未执行(虽然你说能返回JSON,但部分逻辑可能被跳过)。
验证:
- 检查项目依赖中的Jackson版本(比如
jackson-databind),确保是2.9.x或更高; - 查看服务器日志,有没有隐藏的
IllegalAccessError或NoSuchMethodError这类反射异常。
内容的提问来源于stack exchange,提问作者gringogordo

