源码分析 There is no getter for property named '*' in 'class java.lang.String(1)-阿里云开发者社区

开发者社区> 沉默王二> 正文

源码分析 There is no getter for property named '*' in 'class java.lang.String(1)

简介: 源码分析 There is no getter for property named '*' in 'class java.lang.String
+关注继续查看

There is no getter for property named '*' in 'class java.lang.String',此错误之所以出现,是因为mybatis在对parameterType="String"的sql语句做了限制,假如你使用<when test="username != null">这样的条件判断时,就会出现该错误,不过今天我们来刨根问底一下。


###一、错误再现

想要追本溯源,就需要错误再现,那么假设我们有这样一个sql查询:


<select id="getRiskMember" resultMap="BaseResultMap" parameterType="String">
    <include refid="selectMember"/>
    <choose>
  <when test="username != null">
    and username = #{username} 
  </when>
  <otherwise>
    and safetylevel > 1
  </otherwise>
    </choose>
 </select>

parameterType="String",这一点是必须得,参数类型必须是string。

该sql对应的mapper class中对应的方法为List<Member> getRiskMember(String username);,也就是说,传递的参数名为username,正常情况下,这样的配置合情合理。

<when test="username != null">,你有一个对应的test判断语句,也可能是if。

那么这个时候,项目运行该查询语句时,就会抛出There is no getter for property named 'username' in 'class java.lang.String'错误!

###二、解决办法

当然了,如果你没有时间来看源码分析实例的话,我想先告诉你解决办法,免得你被问题困扰。解决办法很简单,你只需要把 <when test="username != null">修改为 <when test="_parameter!= null">就好了,其他地方不需要改动(也就是说and username = #{username}不需要改动为and username = #{_parameter}),修改后的sql语句如下:


<select id="getRiskMember" resultMap="BaseResultMap" parameterType="String">
    <include refid="selectMember"/>
    <choose>
  <when test="_parameter != null">
    and username = #{username} 
  </when>
  <otherwise>
    and safetylevel > 1
  </otherwise>
    </choose>
 </select>


###三、源码分析

当然了,如果你有时间的话,看一看源码分析,或者自己动手尝试一下,我相信你一定会大有所获!


####①、准备源码包

你需要这样两个文件,具体怎么下载我就不多说了,如果你需要的话,也可以加群120926808:


mybatis-3.2.3-sources.jar

mybatis-spring-1.2.2-sources.jar

当然了,你项目中对应的lib包也是相应的版本。


然后,我们把对应的源码进行反编译,生成对应的source,使用的工具是jd-gui.exe。




紧接着,我们来看看如何关联源码包,见下图:


image.png


我已经加载好了,如果是首次的话,可点击edit,在弹出的提示框中选择上一步保存的zip文件。

image.png



####②、测试用例

准备好源码包后,我们来写一个测试用例,直接main方法就可以,当然了项目不同,方法自然不同,简单的如下所示:


public static void main(String[] args) throws IOException {
    SpringUtils.getSpringContext();
    MemberMapper mapper = SpringUtils.getBeansByClassType(MemberMapper.class);
    mapper.getRiskMember("00010001");
}


我们在mapper.getRiskMember("00010001");这行打上断点。


####③、debug调试

直接运行main方法,在断点处F5,进入到MapperProxy.java


public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
  if (Object.class.equals(method.getDeclaringClass())) {
    return method.invoke(this, args);
  }
  final MapperMethod mapperMethod = cachedMapperMethod(method);
  return mapperMethod.execute(sqlSession, args);
 }


可以尾随debug进入到MapperMethod.java

  private <E> Object executeForMany(SqlSession sqlSession, Object[] args) {
    List<E> result;
    Object param = method.convertArgsToSqlCommandParam(args);
    if (method.hasRowBounds()) {
      RowBounds rowBounds = method.extractRowBounds(args);
      result = sqlSession.<E>selectList(command.getName(), param, rowBounds);
    } else {
      result = sqlSession.<E>selectList(command.getName(), param);
    }
    // issue #510 Collections & arrays support
    if (!method.getReturnType().isAssignableFrom(result.getClass())) {
      if (method.getReturnType().isArray()) {
        return convertToArray(result);
      } else {
        return convertToDeclaredCollection(sqlSession.getConfiguration(), result);
      }
    }
    return result;
  }

进入到该方法后,可以一直调试到result = sqlSession.<E>selectList(command.getName(), param);该行代码。此时,你需要按住ctrl键,同时点击鼠标左键,见下图:

image.png


在弹出框中选择open implementation,然后进入到DefaultSqlSession.java


public <E> List<E> selectList(String statement, Object parameter) {
    return this.selectList(statement, parameter, RowBounds.DEFAULT);
  }


在return this.selectList行上打上断点,然后按F8快捷键进入到该方法继续调试,(限于篇幅,省略步骤,后续文章中使用…代替)、直到你进入到CachingExecutor.java


public <E> List<E> query(MappedStatement ms, Object parameterObject, RowBounds rowBounds, ResultHandler resultHandler) throws SQLException {
   BoundSql boundSql = ms.getBoundSql(parameterObject);
   CacheKey key = createCacheKey(ms, parameterObject, rowBounds, boundSql);
   return query(ms, parameterObject, rowBounds, resultHandler, key, boundSql);
 }


tips:猫腻就在BoundSql boundSql = ms.getBoundSql(parameterObject);这行代码的执行过程中。


(…)(省略步骤,个人调试过程中请注意。)


版权声明:本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《阿里云开发者社区用户服务协议》和《阿里云开发者社区知识产权保护指引》。如果您发现本社区中有涉嫌抄袭的内容,填写侵权投诉表单进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

相关文章
深度分析Java的ClassLoader机制(源码级别)
深度分析Java的ClassLoader机制(源码级别) 写在前面:Java中的所有类,必须被装载到jvm中才能运行,这个装载工作是由jvm中的类装载器完成的,类装载器所做的工作实质是把类文件从硬盘读取到内存中,JVM在加载类的时候,都是通过ClassLoader的loadClass()方法来加载class的,loadClass使用双亲委派模式。
1304 0
centos6.9 编译openJdk源码
仿照《深入理解Java虚拟机:JVM高级特性与最佳实践》编译openJdk源码 Linux系统 CentOS release 6.9 (Final) Kernel \r on an \m Bootstrap JDK java-1.
912 0
源码分析 There is no getter for property named '*' in 'class java.lang.String(2)
源码分析 There is no getter for property named '*' in 'class java.lang.String
11 0
源码分析 There is no getter for property named '*' in 'class java.lang.String(1)
源码分析 There is no getter for property named '*' in 'class java.lang.String
16 0
Java 读写锁 ReentrantReadWriteLock 源码分析
原文出处:https://javadoop.com/post/reentrant-read-write-lock 本文内容:读写锁 ReentrantReadWriteLock 的源码分析,基于 Java7/Java8。
815 0
Java集合类源码分析汇总
Java集合类基础:http://www.cnblogs.com/hzmark/archive/2012/12/17/CollectionBase.html ArrayList源码分析:http://www.
805 0
Java并发编程笔记之Semaphore信号量源码分析
JUC 中 Semaphore 的使用与原理分析,Semaphore 也是 Java 中的一个同步器,与 CountDownLatch 和 CycleBarrier 不同在于它内部的计数器是递增的,那么,Semaphore 的内部实现是怎样的呢?   Semaphore 信号量也是Java 中一个同步容器,与CountDownLatch 和 CyclicBarrier 不同之处在于它内部的计数器是递增的。
4074 0
Tensorflow源码解析4 -- 图的节点 - Operation
# 1 概述 上文讲述了TensorFlow的核心对象,计算图Graph。Graph包含两大成员,节点和边。节点即为计算算子Operation,边则为计算数据Tensor。由起始节点Source出发,按照Graph的拓扑顺序,依次执行节点的计算,即可完成整图的计算,最后结束于终止节点Sink,并输出计算结果。 本文会对节点Operation进行详细讲解。 # 2 前端节点数据
791 0
+关注
沉默王二
微信搜索「沉默王二」,回复关键字「00」获取硬核计算机基础资料。
1084
文章
0
问答
文章排行榜
最热
最新
相关电子书
更多
《2021云上架构与运维峰会演讲合集》
立即下载
《零基础CSS入门教程》
立即下载
《零基础HTML入门教程》
立即下载