SpringBoot统一返回处理出现cannot be cast to java.lang.String异常解决

 更新时间:2023年09月01日 10:35:49   作者:伏加特遇上西柚  
这篇文章主要给大家介绍了关于SpringBoot统一返回处理出现cannot be cast to java.lang.String异常解决的相关资料,文中通过图文介绍的非常详细,需要的朋友可以参考下

一 问题出现背景:

在使用 @RestControllerAdvice 和实现 ResponseBodyAdvice controller 层统一返回封装时。当返回字符串时会报 “cannot be cast to java.lang.String” 异常,返回其他类型就无任何问题。

二 解决方案

如果返回的是字符串直接手动封装返回对象转成json字符串返回即可。

完整代码

@RestControllerAdvice
public class ResponseResult implements ResponseBodyAdvice<Object> {
    /**
     * 支持注解@ResponseNotIntercept,使某些方法无需使用Result封装
     *
     * @param returnType 返回类型
     * @param converterType  选择的转换器类型
     * @return true 时会执行beforeBodyWrite方法,false时直接返回给前端
     */
    @Override
    public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
        if (returnType.getDeclaringClass().isAnnotationPresent(ResponseNotIntercept.class)) {
            //若在类中加了@ResponseNotIntercept 则该类中的方法不用做统一的拦截
            return false;
        }
        if (returnType.getMethod().isAnnotationPresent(ResponseNotIntercept.class)) {
            //若方法上加了@ResponseNotIntercept 则该方法不用做统一的拦截
            return false;
        }
        return true;
    }
    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, MediaType selectedContentType,
                                  Class<? extends HttpMessageConverter<?>> selectedConverterType,
                                  ServerHttpRequest request, ServerHttpResponse response) {
        if (body instanceof Result) {
            // 提供一定的灵活度,如果body已经被包装了,就不进行包装
            return body;
        }
        if (body instanceof String) {
            //解决返回值为字符串时,不能正常包装
            return JSON.toJSONString(Result.success(body));
        }
        return Result.success(body);
    }
}

三 异常原因分析

原因:

SpringMVC 默认会注册一些自带的 HttpMessageConvertor (从先后顺序排列分别为ByteArrayHttpMessageConverter、StringHttpMessageConverter、ResourceHttpMessageConverter,SourceHttpMessageConverter、AllEncompassingFormHttpMessageConverter) ,后端服务使用Restful API的形式,前后端得规范一般是json格式, SpringMVC 自带 MappingJackson2HttpMessageConverter ,在依赖中引入 jackson 包后,容器会把 MappingJackson2HttpMessageConverter 自动注册到 messageConverters 链的末尾

当返回的数据是非字符串时使用的 MappingJackson2HttpMessageConverter 写入返回对象。当返回的数据是字符串时,此处得方法是要去循环遍历 HttpMessageConverter 集,因为 StringHttpMessageConverter 会先被遍历到,这时会认为 StringHttpMessageConverter 可以使用,在返回 Result 是使用 ((HttpMessageConverter) converter).write(body, selectedMediaType, outputMessage) ;此方法是父类方法 body 参数类型为 Object ,实际调用的为 StringHttpMessageConverter 中的 addDefaultHeaders(HttpHeaders headers, String s, @Nullable MediaType type) 方法,使用 String 类型的 s 来接收 Result 类型的 body ,类型不匹配则出现 Result cannot be cast to java.lang.String 异常。

源码详细分析:

正常返回:

步骤一:遍历 messageConverters 去判断到 MappingJackson2HttpMessageConverter GenericHttpMessageConverter 类型的 converter

步骤二:进一步判断到 MappingJackson2HttpMessageConverter 可以写入对象类型的数据。

步骤三:调用 beforeBodyWriter 方法将原有的 TestVO 对象数据封装到 Result 对象中。

步骤四:调用 MappingJackson2HttpMessageConverter 中的 wirte 方法(代码中用接口类型接收的)

步骤五:通过 MappingJackson2HttpMessageConverter 继承关系发现其write方法在父类 AbstractHttpMessageConverter 中,在 write 方法中调用本类中addDefaultHeaders 方法向输出消息添加默认报头。(此处应注意)

步骤六:将封装好的Result对象返回给前端

返回为字符串异常

步骤一:遍历 messageConverters 去判断到 StringHttpMessageConverter 是null;

步骤二:进一步判断到 StringHttpMessageConverter 可以写入String类型的数据。

步骤三:调用 beforeBodyWriter 方法将原有的 String 类型数据封装到 Result 对象中。

步骤四:调用 StringHttpMessageConverter 中的 wirte 方法(代码中用接口类型接收的)

步骤五

调用父类 AbstractHttpMessageConverter 中的 write 方法,由于 StringHttpMessageConverter 重写了 addDefaultHeaders 方法,故 write 中调用子类中的 addDefaultHeaders 。由于父类中参数t为对象类型,对应子类中接收的s为String类型故会出现类型转换异常 Result cannot be cast to java.lang.String (此处应注意)

总结 

到此这篇关于SpringBoot统一返回处理出现cannot be cast to java.lang.String异常解决的文章就介绍到这了,更多相关cannot be cast to java.lang.String异常内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • SpringBoot 整合 Spring-Session 实现分布式会话项目实战

    SpringBoot 整合 Spring-Session 实现分布式会话项目实战

    本文主要介绍了SpringBoot 整合 Spring-Session 实现分布式会话项目实战,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-07-07
  • mybatis resultType自带数据类型别名解读

    mybatis resultType自带数据类型别名解读

    MyBatis为了简化开发,通过org.apache.ibatis.type.TypeAliasRegistry为常见类定义了别名,这些别名包括基本数据类型及其数组、集合类型等,如string对应java.lang.String,int对应java.lang.Integer等,此外,还有特殊前缀的别名如_int对应int类型
    2024-10-10
  • java集合中list的用法代码示例

    java集合中list的用法代码示例

    这篇文章主要介绍了java集合中list的用法代码示例,分享了相关代码,具有一定参考价值,需要的朋友可以了解下。
    2017-11-11
  • elasticsearch源码分析index action实现方式

    elasticsearch源码分析index action实现方式

    这篇文章主要为大家介绍了elasticsearch源码分析index action实现方式,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-04-04
  • Java编程倒计时实现方法示例

    Java编程倒计时实现方法示例

    这篇文章主要介绍了Java编程倒计时实现的三个示例,三种实现方法,具有一定参考价值,需要的朋友可以了解下。
    2017-09-09
  • 使用Java编写图形化的菜单的教程

    使用Java编写图形化的菜单的教程

    这篇文章主要介绍了使用Java编写图形化的菜单的教程,需要的朋友可以参考下
    2015-10-10
  • 通过Java连接SQL Server数据库的超详细操作流程

    通过Java连接SQL Server数据库的超详细操作流程

    java相对于其他语言(例如c,c++等)连接数据库要方便得多,那么如何连接呢?下面这篇文章主要给大家介绍了关于通过Java连接SQL Server数据库的超详细操作流程,需要的朋友可以参考下
    2023-03-03
  • Spring Boot配置拦截器及实现跨域访问的方法

    Spring Boot配置拦截器及实现跨域访问的方法

    这篇文章主要介绍了Spring Boot配置拦截器及实现跨域访问的方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2018-12-12
  • Java版的7种单例模式写法示例

    Java版的7种单例模式写法示例

    这篇文章主要给大家介绍了关于Java版的7种单例模式写法,文中通过示例代码介绍的非常详细,对大家学习或者使用Java具有一定的参考学习价值,需要的朋友们下面来一起学习学习吧
    2019-10-10
  • 一起聊聊Java中的自定义异常

    一起聊聊Java中的自定义异常

    在学习Java的过程中,想必大家都一定学习过异常这个篇章,异常的基本特性和使用这里就不再多讲了。本文就来和大家讲讲如何自定义异常
    2022-08-08

最新评论