{"record":{"id":"a25b17bc0c18c764","repo":"mybatis/mybatis-3","slug":"error-evaluating-expression-expression-a25b17","errorCode":null,"errorMessage":"Error evaluating expression '\" + expression + \"'. Cause: \" + e","messagePattern":"Error evaluating expression '\" \\+ expression \\+ \"'\\. Cause: \" \\+ e","errorType":"exception","errorClass":"BuilderException","httpStatus":null,"severity":"error","filePath":"src/main/java/org/apache/ibatis/scripting/xmltags/OgnlCache.java","lineNumber":49,"sourceCode":" *\n * @see <a href='https://github.com/mybatis/old-google-code-issues/issues/342'>Issue 342</a>\n */\npublic final class OgnlCache {\n\n  private static final OgnlMemberAccess MEMBER_ACCESS = new OgnlMemberAccess();\n  private static final OgnlClassResolver CLASS_RESOLVER = new OgnlClassResolver();\n  private static final Map<String, Object> expressionCache = new ConcurrentHashMap<>();\n\n  private OgnlCache() {\n    // Prevent Instantiation of Static Class\n  }\n\n  public static Object getValue(String expression, Object root) {\n    try {\n      OgnlContext context = Ognl.createDefaultContext(root, MEMBER_ACCESS, CLASS_RESOLVER, null);\n      return Ognl.getValue(parseExpression(expression), context, root);\n    } catch (OgnlException e) {\n      throw new BuilderException(\"Error evaluating expression '\" + expression + \"'. Cause: \" + e, e);\n    }\n  }\n\n  private static Object parseExpression(String expression) throws OgnlException {\n    Object node = expressionCache.get(expression);\n    if (node == null) {\n      node = Ognl.parseExpression(expression);\n      expressionCache.put(expression, node);\n    }\n    return node;\n  }\n\n}\n","sourceCodeStart":31,"sourceCodeEnd":63,"githubUrl":"https://github.com/mybatis/mybatis-3/blob/008069adb1b089579b5dcba87ee591908b263274/src/main/java/org/apache/ibatis/scripting/xmltags/OgnlCache.java#L31-L63","documentation":"OgnlCache.getValue() wraps any OGNL runtime failure in a BuilderException whose message embeds the failing expression and the original OgnlException. This is the generic failure point for every OGNL evaluation MyBatis performs: test=\"...\" conditions in <if>/<when>, and ${...} string substitutions. The cause chain is preserved, so the root reason (syntax error, missing property, null navigation, wrong method signature) is in the nested exception.","triggerScenarios":"A test=\"usr.name != null\" where the parameter has no getName(); OGNL syntax errors like test=\"a == && b\"; calling a method that does not exist in test=\"list.size() > 0\" when the property is not a list; navigating into a null intermediate object with an invalid path; using ${} with a property name that is absent from the parameter map.","commonSituations":"Renaming a Java field/getter without updating mapper XML; copy-pasting an <if test> from another statement with a different parameter name; @Param name mismatch between mapper interface and XML; upgrading MyBatis/OGNL versions where grammar got stricter; null parameter passed to a dynamic statement.","solutions":["Read the nested Cause in the stack trace: it names the exact property/method OGNL could not resolve.","Align the property path in test= or ${} with the actual parameter (check @Param annotations on the mapper method).","For null-safety, guard navigation: test=\"user != null and user.name != null\".","Add the missing getter or @Param to the parameter object."],"exampleFix":"// before\n<if test=\"name != null\">AND name = #{name}</if>\n<!-- mapper: find(@Param('userName') String name) -->\n// after\n<if test=\"userName != null\">AND name = #{userName}</if>","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"try { return sqlSession.selectList(stmt, param); }\ncatch (BuilderException e) {\n  Throwable root = e.getCause(); // OgnlException with the real reason\n  log.error(\"OGNL failed for {}: {}\", stmt, root.getMessage());\n  throw e;\n}","preventionTips":["Keep @Param names and XML test=/${} expressions in one review unit when changing either side.","Null-guard navigation in tests: 'a != null and a.b != null'.","Write one smoke test per mapper method so OGNL regressions surface in CI, not production."],"tags":["mybatis","ognl","dynamic-sql","builder-exception"],"backgroundTag":null,"analyzedSha":"008069adb1b089579b5dcba87ee591908b263274","analyzedAt":"2026-08-14T13:07:10.264Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}