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


    一 问题出现背景:

    在使用@RestControllerAdvice和实现ResponseBodyAdvicecontroller层统一返回封装时。当返回字符串时会报 “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);
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37

    三 异常原因分析

    原因:

    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(此处应注意)

    在这里插入图片描述

  • 相关阅读:
    【Windows日志】记录系统事件的日志
    线索二叉树操作详解(详细图例+cpp实现+源码)
    华为ensp:vrrp双机热备负载均衡
    技术解读倚天 ECS 实例 — Arm 芯片的 Python-AI 算力优化
    记录使用layui弹窗实现签名、签字
    shiro设置url过滤配置详解
    高通Android10 移植exFat格式
    基于单片机的空气质量检测系统
    上海亚商投顾:沪指放量反弹 两市超4500股飘红
    lamada List对象属性值转数组array
  • 原文地址:https://blog.csdn.net/weixin_43811057/article/details/127655041