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异常内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • Jmeter安装及配置教程详解

    Jmeter安装及配置教程详解

    很多朋友私信小编Jmeter安装及配置教程能出一期教程吗?正巧赶上疫情,不是太忙,下面小编把Jmeter安装及配置教程分享到脚本之家平台,感兴趣的朋友跟随小编一起看看吧
    2021-12-12
  • Java实例精炼掌握语法

    Java实例精炼掌握语法

    本章节我们将为大家介绍 Java 实现几大基础问题,通过实例学习我们可以更快的掌握 Java 的应用,感兴趣的朋友来看看吧
    2022-04-04
  • jsp+servlet实现简单登录页面功能(附demo)

    jsp+servlet实现简单登录页面功能(附demo)

    本文主要介绍了jsp+servlet实现简单登录页面功能登录成功跳转新页面,登录失败在原登录界面提示登录失败信息,对初学者有一定的帮助,感兴趣的可以了解一下
    2021-07-07
  • Java8 Stream 流常用方法合集

    Java8 Stream 流常用方法合集

    这篇文章主要介绍了 Java8 Stream 流常用方法合集,Stream 是 Java8 中处理集合的关键抽象概念,它可以指定你希望对集合进行的操作,可以执行非常复杂的查找、过滤和映射数据等操作,下文相关资料,需要的朋友可以参考一下
    2022-04-04
  • Java用栈实现综合计算器

    Java用栈实现综合计算器

    栈(stack)又名堆栈,它是一种运算受限的线性表,下面看一下如何在Java中,利用数组实现模拟一个栈,感兴趣的朋友跟随小编一起看看吧
    2022-06-06
  • Spring MVC中@Controller和@RequestMapping注解使用

    Spring MVC中@Controller和@RequestMapping注解使用

    这篇文章主要介绍了Spring MVC中@Controller和@RequestMapping注解使用,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-02-02
  • java  Vector和ArrayList的分析及比较

    java Vector和ArrayList的分析及比较

    这篇文章主要介绍了java Vector和ArrayList的分析及比较的相关资料,Vector是多线程安全的,而ArrayList不是,本文主要做对比对这两个方法,需要的朋友可以参考下
    2016-11-11
  • IDEA整合SSM框架实现网页上显示数据

    IDEA整合SSM框架实现网页上显示数据

    最近做了个小项目,该项目包在intellij idea中实现了ssm框架的整合以及实现访问,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2021-05-05
  • Java枚举(enum) 详解7种常见的用法

    Java枚举(enum) 详解7种常见的用法

    这篇文章主要介绍了Java枚举(enum) 详解7种常见的用法,具有一定的参考价值,有需要的可以了解一下。
    2016-11-11
  • Java数组实例练习题整理

    Java数组实例练习题整理

    在本篇文章中小编给各位分享的是关于Java数组实例练习题以及相关代码整理,有需要的朋友们跟着学习下。
    2019-07-07

最新评论