There is no getter for property named & amp; #39; * & amp; #39; in & amp; #39; class java. lang. string & amp; #39; source code analysis

Source: Internet
Author: User

There is no getter for property named & #39; * & #39; in & #39; class java. lang. String & #39; source code analysis

There is no getter for property named '*' in 'class java.lang.String'This error occurs because mybatis isparameterType="String"SQL statement, if you use This error will occur when such a condition is determined, but today we will give a thorough explanation.

I. Error Reproduction

If you want to trace the source, you need to reproduce the error. Suppose we have an SQL query:

<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"This is required. The parameter type must be string. The corresponding method in mapper class corresponding to this SQL statement is List getRiskMember(String username); That is to say, the passed parameter is named username. Normally, this configuration is reasonable. , You have a test judgment statement, or if. When the project runs the query statement There is no getter for property named 'username' in 'class java.lang.String'Error! Ii. Solution

Of course, if you don't have time to look at the source code analysis instance, I 'd like to tell you the solution first, so that you will not be troubled by the problem. The solution is simple. Change That's it. You don't need to change it elsewhere (that isand username = #{username}Do not changeand username = #{_parameter}), The modified SQL statement is as follows:

<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>
Iii. Source Code Analysis

Of course, if you have time, take a look at the source code analysis, or try it on your own. I believe you will surely gain a lot!

① Prepare the source code package

You need to download these two files. I will not talk about how to download them. If you need them, add the group 120926808:

Mybatis-3.2.3-sources.jar mybatis-spring-1.2.2-sources.jar

Of course, the corresponding lib package in your project is also the corresponding version.

Then, we decompile the source code and generate the source code. The tool used is jd-gui.exe.

Next, let's take a look at how to associate the source code package. See:

I have loaded the file. If it is the first time, click edit and select the zip file saved in the previous step in the pop-up box.

② Test Cases

After preparing the source code package, let's write a test case and use the main method directly. Of course, the project is different, and the method is naturally different. The following is a simple example:

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

Inmapper.getRiskMember("00010001");This line is broken.

③ Debug

Run the main method directly, F5 at the breakpoint, and go to 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); }

You can follow debug to access MapperMethod. java.

  private 
  
    Object executeForMany(SqlSession sqlSession, Object[] args) {    List
   
     result;    Object param = method.convertArgsToSqlCommandParam(args);    if (method.hasRowBounds()) {      RowBounds rowBounds = method.extractRowBounds(args);      result = sqlSession.
    
     selectList(command.getName(), param, rowBounds);    } else {      result = sqlSession.
     
      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;  }
     
    
   
  

After entering this method, you can continue debuggingresult = sqlSession. selectList(command.getName(), param); This line of code. At this point, you need to press ctrl and click the left mouse button, see:

In the pop-up box, select open implementation and enter defasqlsqlsession. java

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

Inreturn this.selectListPlace a breakpoint on the line, and press the F8 shortcut to continue debugging... ), Until you enter CachingExecutor. java

 public 
  
    List
   
     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: trickyBoundSql boundSql = ms.getBoundSql(parameterObject);This line of code is being executed.

(...) (Skip the steps. Note the steps during personal debugging .)

Until you enter the DynamicContext. java class

  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());  }

At this point, you may wish to wait a moment, look at the overall code of this class, you will find:

  public static final String PARAMETER_OBJECT_KEY = "_parameter";  public static final String DATABASE_ID_KEY = "_databaseId";

There are two constants here, of course, but here, you may find"_parameter"This keyword, but it cannot be explained at this moment. Rememberbindings.put(PARAMETER_OBJECT_KEY, parameterObject);AndContextMap bindingsObject.

Key1: _ Parameter

(...) (Skip the steps. Note the steps during personal debugging .)

Then, we enter MixedSqlNode. java

  public boolean apply(DynamicContext context) {    for (SqlNode sqlNode : contents) {      sqlNode.apply(context);    }    return true;  }

This apply method is very interesting. The SQL statements configured in xml are converted to standard SQL statements (referred to as standard, the SQL statement is a string that can execute pre-processing SQL queries.

In the second loop, you can see the prototype of SQL. Continue.

(...) (Skip the steps. Note the steps during personal debugging .)

Until you find that,The sqlNode type is ChooseSqlNode.At this time, can you have thought of the following:

<code class="language-xml hljs "><choose>        <when test="_parameter != null"></when></choose></code>

It's nice to get things started to become clear.

(...) (Skip the steps. Note the steps during personal debugging .)

Continue debugging until you enter 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;  }
The expression value is username != nullThe parameterObject value is {_parameter=00010001, _databaseId=null}The two parameters seem to have a relationship, but they are a few steps away from the source. Please continue.

Then we enter 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);    }  }

Go to 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:
1.parseExpression(expression)Is Node, and its value isusername != null.
2. The root type isDynamicContext$ContextMap (id=41)The value is{_parameter=00010001, _databaseId=null}

(...) (Skip the steps. Note the steps during personal debugging .)

When the execution continues, it returns to defasqlsqlsession. java

  public 
  
    List
   
     selectList(String statement, Object parameter, RowBounds rowBounds) {    try {      MappedStatement ms = configuration.getMappedStatement(statement);      List
    
      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();    }  }
    
   
  

The error has been thrown. See

Authorization/tMnPwLSjrLrDz/authorization + o6zL + authorization/be0seDS67mkvt + jrL/J0tS/authorization + DQo8cHJlIGNsYXNzPQ = "brush: java;"> 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;  }

In this case, we can combine the content given by key2 to know that{_parameter=00010001, _databaseId=null}Match to porpertyusernameThe value is impossible. In this way, the program will throworg.mybatis.spring.MyBatisSystemException: nested exception is org.apache.ibatis.reflection.ReflectionException: There is no getter for property named 'username' in 'class java.lang.String'Error!
Shouldn't you put off a heavy shell and find out where there is a blue sky -- Jay Chou's snail

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.