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

直到你进入到DynamicContext.java类时


public DynamicContext(Configuration configuration, Object parameterObject) {
    if (parameterObject != null && !(parameterObject instanceof Map)) {
      MetaObject metaObject = configuration.newMetaObject(parameterObject);
      bindings = new ContextMap(metaObject);
    } else {
      bindings = new ContextMap(null);
    }
    bindings.put(PARAMETER_OBJECT_KEY, parameterObject);
    bindings.put(DATABASE_ID_KEY, configuration.getDatabaseId());
  }

此时,你不妨wait a moment,翻看一下该类的整体代码,你会发现:


 public static final String PARAMETER_OBJECT_KEY = "_parameter";

 public static final String DATABASE_ID_KEY = "_databaseId";

1

2

这里有两个常量,当然了,但看此处,也许你会发现"_parameter"这个关键字,但这时还说明不了什么,你且记住bindings.put(PARAMETER_OBJECT_KEY, parameterObject);,同时对ContextMap bindings对象留有一点印象。


key1:_parameter


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


然后,我们进入MixedSqlNode.java


 public boolean apply(DynamicContext context) {

   for (SqlNode sqlNode : contents) {

     sqlNode.apply(context);

   }

   return true;

 }


该apply方法就非常有意思了,xml里配置的sql语句,会通过该方法转换为标准的sql(称之为标准,是值这形成的sql语句就是能够执行预处理sql查询的字符串),你不妨慢一点执行该循环语句。


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


第二次循环的时候,你就可以看到sql的雏形了,那么请继续。


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


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


直到你发现,sqlNode的类型为ChooseSqlNode,此时,你是否已经能联想到以下内容:


<choose>

 <when test="_parameter != null">

1

2

事情开始变得明朗起来,真好。


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


继续调试,直到你进入到ExpressionEvaluator.java


 public boolean evaluateBoolean(String expression, Object parameterObject) {

   Object value = OgnlCache.getValue(expression, parameterObject);

   if (value instanceof Boolean) return (Boolean) value;

   if (value instanceof Number) return !new BigDecimal(String.valueOf(value)).equals(BigDecimal.ZERO);

   return value != null;

 }

1

2

3

4

5

6

expression的值为username != null

parameterObject的值为{_parameter=00010001, _databaseId=null}

以上两个参数之间好像有点关系,但离源泉处还差那么几步,请继续。

紧接着,我们进入到OgnlCache.java


public static Object getValue(String expression, Object root) {
    try {
      return Ognl.getValue(parseExpression(expression), root);
    } catch (OgnlException e) {
      throw new BuilderException("Error evaluating expression '" + expression + "'. Cause: " + e, e);
    }
  }


进入到OgnlCache.java

  private static Object parseExpression(String expression) throws OgnlException {
    try {
      Node node = expressionCache.get(expression);
      if (node == null) {
        node = new OgnlParser(new StringReader(expression)).topLevelExpression();
        expressionCache.put(expression, node);
      }
      return node;
    } catch (ParseException e) {
      throw new ExpressionSyntaxException(expression, e);
    } catch (TokenMgrError e) {
      throw new ExpressionSyntaxException(expression, e);
    }
  }

key2:


parseExpression(expression)的类型为Node,其值为username != null。

root的类型为DynamicContext$ContextMap (id=41),其值为{_parameter=00010001, _databaseId=null}

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


当再继续执行的话,就回到了DefaultSqlSession.java

  public <E> List<E> selectList(String statement, Object parameter, RowBounds rowBounds) {
    try {
      MappedStatement ms = configuration.getMappedStatement(statement);
      List<E> result = executor.query(ms, wrapCollection(parameter), rowBounds, Executor.NO_RESULT_HANDLER);
      return result;
    } catch (Exception e) {
      throw ExceptionFactory.wrapException("Error querying database.  Cause: " + e, e);
    } finally {
      ErrorContext.instance().reset();
    }
  }

此时错误已经抛出了,见下图

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



到了这,异常是找到怎么抛出了,但整体看上来,好像又缺点什么,没错,由于eclipse中无法再看到Ognl.getValue(parseExpression(expression), root);,所以就会造成困扰,我们通过反编译工具,可以看到getValue方法。


public static Object getValue(Object tree, Object root)
    throws OgnlException
  {
    return getValue(tree, root, null);
  }


public static Object getValue(Object tree, Map context, Object root)
    throws OgnlException
  {
    return getValue(tree, context, root, null);
  }


public static Object getValue(Object tree, Map context, Object root, Class resultType)
    throws OgnlException
  {
    OgnlContext ognlContext = (OgnlContext)addDefaultContext(root, context);
    Object result = ((Node)tree).getValue(ognlContext, root);
    if (resultType != null) {
      result = getTypeConverter(context).convertValue(context, root, null, null, result, resultType);
    }
    return result;
  }


此时再结合key2给出的内容,我们可以知道,要在{_parameter=00010001, _databaseId=null}匹配到porperty为username的值是不可能的啦,这样的话,程序就会抛出org.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.reflection.ReflectionException: There is no getter for property named 'username' in 'class java.lang.String'错误了!


最近,有不少读者问我是怎么学习的,那我干脆就把我看过的一些优质书籍贡献出来:


计算机基础入门推荐:《程序是怎样跑起来的》、《网络是怎样连接的》、《计算机是怎样跑起来的的》


进一步认识计算机网络:《计算机网络:自顶向下》、《图解http》


数据结构+算法入门:《大话数据结构》、《阿哈算法》


算法进阶:《算法第四版》、《编程珠玑》


由于我是 Java 技术栈的,顺便推荐几本 Java 的书籍,从左到由的顺序看到


Java:《Java核心技术卷1》、《编程思想》、《深入理解Java虚拟机》、《effective Java》、《Java并发编程的艺术》


数据库:《mysql必知必会》、《MySQL技术内幕:InnoDB存储引擎》


就先介绍这么多,这些都是最基础最核心的,希望对那些不知道看什么书的同学有所帮助。


上一篇:如何使用Angular的@Input()装饰器


下一篇:c#开源消息队列中间件EQueue 教程