MyBatis测试报错:Cannot determine value type from string 'xxx'的解决办法

作者:大先生哈哈哈 时间:2023-03-26 07:19:46 

关于[Cannot determine value type from string ‘xxx’]的问题

1、产生

实体类Student中属性有id,name,email,age,未使用无参构造器

在mapper.xml中只查询name,email,age

测试时报错

Cannot determine value type from string '张三'

2、解决

实体类Student中添加无参构造器

得到结果

Student{id=null, name='张三', email='zhangsan@126.com', age=22}

3、探究

跟踪源码

org.apache.ibatis.executor.resultset.DefaultResultSetHandler

这个类有个方法createResultObject

private Object createResultObject(ResultSetWrapper rsw, ResultMap resultMap, List<Class<?>> constructorArgTypes, List<Object> constructorArgs, String columnPrefix)
     throws SQLException {
   final Class<?> resultType = resultMap.getType();
   final MetaClass metaType = MetaClass.forClass(resultType, reflectorFactory);
   final List<ResultMapping> constructorMappings = resultMap.getConstructorResultMappings();
   if (hasTypeHandlerForResultObject(rsw, resultType)) {
     return createPrimitiveResultObject(rsw, resultMap, columnPrefix);
   } else if (!constructorMappings.isEmpty()) {
     return createParameterizedResultObject(rsw, resultType, constructorMappings, constructorArgTypes, constructorArgs, columnPrefix);
   } else if (resultType.isInterface() || metaType.hasDefaultConstructor()) {
     return objectFactory.create(resultType);
   } else if (shouldApplyAutomaticMappings(resultMap, false)) {
     return createByConstructorSignature(rsw, resultType, constructorArgTypes, constructorArgs);
   }
   throw new ExecutorException("Do not know how to create an instance of " + resultType);
 }

这个方法是根据结果集返回值的类型创建出相应的bean字段对象

  • 当实体使用无参构造器时

mybatis会调用createResultObject方法中objectFactory.create(resultType),使用无参构造器创建对象

private  <T> T instantiateClass(Class<T> type, List<Class<?>> constructorArgTypes, List<Object> constructorArgs) {
   try {
     Constructor<T> constructor;
     if (constructorArgTypes == null || constructorArgs == null) {
       constructor = type.getDeclaredConstructor();
       try {
         return constructor.newInstance();
       } catch (IllegalAccessException e) {
         if (Reflector.canControlMemberAccessible()) {
           constructor.setAccessible(true);
           return constructor.newInstance();
         } else {
           throw e;
         }
       }
     }
     constructor = type.getDeclaredConstructor(constructorArgTypes.toArray(new Class[0]));
     try {
       return constructor.newInstance(constructorArgs.toArray(new Object[0]));
     } catch (IllegalAccessException e) {
       if (Reflector.canControlMemberAccessible()) {
         constructor.setAccessible(true);
         return constructor.newInstance(constructorArgs.toArray(new Object[0]));
       } else {
         throw e;
       }
     }
   } catch (Exception e) {
     String argTypes = Optional.ofNullable(constructorArgTypes).orElseGet(Collections::emptyList)
         .stream().map(Class::getSimpleName).collect(Collectors.joining(","));
     String argValues = Optional.ofNullable(constructorArgs).orElseGet(Collections::emptyList)
         .stream().map(String::valueOf).collect(Collectors.joining(","));
     throw new ReflectionException("Error instantiating " + type + " with invalid types (" + argTypes + ") or values (" + argValues + "). Cause: " + e, e);
   }
 }

当实体使用有参构造参数

mybatis会调用createResultObject方法中createByConstructorSignature(rsw, resultType, constructorArgTypes, constructorArgs);

private Object createUsingConstructor(ResultSetWrapper rsw, Class<?> resultType, List<Class<?>> constructorArgTypes, List<Object> constructorArgs, Constructor<?> constructor) throws SQLException {
   boolean foundValues = false;
   for (int i = 0; i < constructor.getParameterTypes().length; i++) {
     Class<?> parameterType = constructor.getParameterTypes()[i];
     String columnName = rsw.getColumnNames().get(i);
     TypeHandler<?> typeHandler = rsw.getTypeHandler(parameterType, columnName);
     Object value = typeHandler.getResult(rsw.getResultSet(), columnName);
     constructorArgTypes.add(parameterType);
     constructorArgs.add(value);
     foundValues = value != null || foundValues;
   }
   return foundValues ? objectFactory.create(resultType, constructorArgTypes, constructorArgs) : null;
 }

这个代码片段里面有个TypeHandler,这个是mybatis的类型处理器,用来处理 JavaType 与 JdbcType 之间的转换。

由代码我们看出,当实体使用有参构造函数时,会遍历有参构造参数个数,根据有参构造参数下标 查找相应的数据库字段名称,根据有参构造字段类型以及数据库字段名称找类型处理器。然后使用TypeHandler来处理JavaType 与 JdbcType 之间的转换。当转换异常,就会报错

4、总结

解决Cannot determine value type from string 'xxx&rsquo;的方法有2种

  • 实体加无参构造参数

  • mapper.xml中查询的数据库字段属性的类型要和有参构造器的字段类型一一匹配;查询字段的个数要和有参构造器个数一样

来源:https://blog.csdn.net/weixin_45966334/article/details/125925698

标签:mybatis,测试,报错
0
投稿

猜你喜欢

  • 浅谈android @id和@+id的区别

    2021-10-28 06:06:09
  • 一文让你搞懂如何手写一个redis分布式锁

    2023-11-29 02:46:30
  • 学习Java的9张思维导图

    2021-06-10 03:38:18
  • 基于Apache组件分析对象池原理的实现案例分析

    2023-11-05 16:55:57
  • Android简单实现一个颜色渐变的ProgressBar的方法

    2023-07-23 00:30:12
  • android在连拍菜单中增加连拍张数选项功能实现代码

    2023-05-27 19:08:38
  • IntelliJ IDEA基于SpringBoot如何搭建SSM开发环境的步骤详解

    2022-11-24 12:10:39
  • Android中协调滚动布局的实现代码

    2023-11-07 20:37:05
  • Android单片机与蓝牙模块通信实例代码

    2023-02-21 17:21:05
  • Hutool开发MapUtil工具类使用示例

    2022-10-21 22:49:27
  • ContentProvider启动流程示例解析

    2023-07-31 03:57:34
  • java操作mongodb示例分享

    2023-09-07 19:00:02
  • C#事件订阅发布实现原理详解

    2022-10-15 20:36:35
  • Android实现点击缩略图放大效果

    2022-11-10 21:47:23
  • Java中Lambda表达式和函数式接口的使用和特性

    2023-06-20 20:05:42
  • Java线程生命周期图文详细讲解

    2022-07-17 05:22:32
  • Android 仿支付宝中的余额宝收益进度条

    2022-11-23 03:58:33
  • C# 抽象类,抽象属性,抽象方法(实例讲解)

    2022-03-14 09:22:16
  • 使用C#开发OPC Server服务器源码解析

    2021-05-30 04:30:14
  • c#将字节数组转成易读的字符串的实现

    2022-03-02 21:38:31
  • asp之家 软件编程 m.aspxhome.com