ParameterExpression.java

  1. /*
  2.  *    Copyright 2009-2023 the original author or authors.
  3.  *
  4.  *    Licensed under the Apache License, Version 2.0 (the "License");
  5.  *    you may not use this file except in compliance with the License.
  6.  *    You may obtain a copy of the License at
  7.  *
  8.  *       https://www.apache.org/licenses/LICENSE-2.0
  9.  *
  10.  *    Unless required by applicable law or agreed to in writing, software
  11.  *    distributed under the License is distributed on an "AS IS" BASIS,
  12.  *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  13.  *    See the License for the specific language governing permissions and
  14.  *    limitations under the License.
  15.  */
  16. package org.apache.ibatis.builder;

  17. import java.util.HashMap;

  18. /**
  19.  * Inline parameter expression parser. Supported grammar (simplified):
  20.  *
  21.  * <pre>
  22.  * inline-parameter = (propertyName | expression) oldJdbcType attributes
  23.  * propertyName = /expression language's property navigation path/
  24.  * expression = '(' /expression language's expression/ ')'
  25.  * oldJdbcType = ':' /any valid jdbc type/
  26.  * attributes = (',' attribute)*
  27.  * attribute = name '=' value
  28.  * </pre>
  29.  *
  30.  * @author Frank D. Martinez [mnesarco]
  31.  */
  32. public class ParameterExpression extends HashMap<String, String> {

  33.   private static final long serialVersionUID = -2417552199605158680L;

  34.   public ParameterExpression(String expression) {
  35.     parse(expression);
  36.   }

  37.   private void parse(String expression) {
  38.     int p = skipWS(expression, 0);
  39.     if (expression.charAt(p) == '(') {
  40.       expression(expression, p + 1);
  41.     } else {
  42.       property(expression, p);
  43.     }
  44.   }

  45.   private void expression(String expression, int left) {
  46.     int match = 1;
  47.     int right = left + 1;
  48.     while (match > 0) {
  49.       if (expression.charAt(right) == ')') {
  50.         match--;
  51.       } else if (expression.charAt(right) == '(') {
  52.         match++;
  53.       }
  54.       right++;
  55.     }
  56.     put("expression", expression.substring(left, right - 1));
  57.     jdbcTypeOpt(expression, right);
  58.   }

  59.   private void property(String expression, int left) {
  60.     if (left < expression.length()) {
  61.       int right = skipUntil(expression, left, ",:");
  62.       put("property", trimmedStr(expression, left, right));
  63.       jdbcTypeOpt(expression, right);
  64.     }
  65.   }

  66.   private int skipWS(String expression, int p) {
  67.     for (int i = p; i < expression.length(); i++) {
  68.       if (expression.charAt(i) > 0x20) {
  69.         return i;
  70.       }
  71.     }
  72.     return expression.length();
  73.   }

  74.   private int skipUntil(String expression, int p, final String endChars) {
  75.     for (int i = p; i < expression.length(); i++) {
  76.       char c = expression.charAt(i);
  77.       if (endChars.indexOf(c) > -1) {
  78.         return i;
  79.       }
  80.     }
  81.     return expression.length();
  82.   }

  83.   private void jdbcTypeOpt(String expression, int p) {
  84.     p = skipWS(expression, p);
  85.     if (p < expression.length()) {
  86.       if (expression.charAt(p) == ':') {
  87.         jdbcType(expression, p + 1);
  88.       } else if (expression.charAt(p) == ',') {
  89.         option(expression, p + 1);
  90.       } else {
  91.         throw new BuilderException("Parsing error in {" + expression + "} in position " + p);
  92.       }
  93.     }
  94.   }

  95.   private void jdbcType(String expression, int p) {
  96.     int left = skipWS(expression, p);
  97.     int right = skipUntil(expression, left, ",");
  98.     if (right <= left) {
  99.       throw new BuilderException("Parsing error in {" + expression + "} in position " + p);
  100.     }
  101.     put("jdbcType", trimmedStr(expression, left, right));
  102.     option(expression, right + 1);
  103.   }

  104.   private void option(String expression, int p) {
  105.     int left = skipWS(expression, p);
  106.     if (left < expression.length()) {
  107.       int right = skipUntil(expression, left, "=");
  108.       String name = trimmedStr(expression, left, right);
  109.       left = right + 1;
  110.       right = skipUntil(expression, left, ",");
  111.       String value = trimmedStr(expression, left, right);
  112.       put(name, value);
  113.       option(expression, right + 1);
  114.     }
  115.   }

  116.   private String trimmedStr(String str, int start, int end) {
  117.     while (str.charAt(start) <= 0x20) {
  118.       start++;
  119.     }
  120.     while (str.charAt(end - 1) <= 0x20) {
  121.       end--;
  122.     }
  123.     return start >= end ? "" : str.substring(start, end);
  124.   }

  125. }