View Javadoc
1   /**
2    *    Copyright 2009-2015 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    *       http://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  
18  import java.util.HashMap;
19  
20  /**
21   * Inline parameter expression parser. Supported grammar (simplified):
22   * 
23   * <pre>
24   * inline-parameter = (propertyName | expression) oldJdbcType attributes
25   * propertyName = /expression language's property navigation path/
26   * expression = '(' /expression language's expression/ ')'
27   * oldJdbcType = ':' /any valid jdbc type/
28   * attributes = (',' attribute)*
29   * attribute = name '=' value
30   * </pre>
31   */
32  /**
33   * @author Frank D. Martinez [mnesarco]
34   */
35  public class ParameterExpression extends HashMap<String, String> {
36  
37    private static final long serialVersionUID = -2417552199605158680L;
38  
39    public ParameterExpression(String expression) {
40      parse(expression);
41    }
42  
43    private void parse(String expression) {
44      int p = skipWS(expression, 0);
45      if (expression.charAt(p) == '(') {
46        expression(expression, p + 1);
47      } else {
48        property(expression, p);
49      }
50    }
51  
52    private void expression(String expression, int left) {
53      int match = 1;
54      int right = left + 1;
55      while (match > 0) {
56        if (expression.charAt(right) == ')') {
57          match--;
58        } else if (expression.charAt(right) == '(') {
59          match++;
60        }
61        right++;
62      }
63      put("expression", expression.substring(left, right - 1));
64      jdbcTypeOpt(expression, right);
65    }
66  
67    private void property(String expression, int left) {
68      if (left < expression.length()) {
69        int right = skipUntil(expression, left, ",:");
70        put("property", trimmedStr(expression, left, right));
71        jdbcTypeOpt(expression, right);
72      }
73    }
74  
75    private int skipWS(String expression, int p) {
76      for (int i = p; i < expression.length(); i++) {
77        if (expression.charAt(i) > 0x20) {
78          return i;
79        }
80      }
81      return expression.length();
82    }
83  
84    private int skipUntil(String expression, int p, final String endChars) {
85      for (int i = p; i < expression.length(); i++) {
86        char c = expression.charAt(i);
87        if (endChars.indexOf(c) > -1) {
88          return i;
89        }
90      }
91      return expression.length();
92    }
93  
94    private void jdbcTypeOpt(String expression, int p) {
95      p = skipWS(expression, p);
96      if (p < expression.length()) {
97        if (expression.charAt(p) == ':') {
98          jdbcType(expression, p + 1);
99        } else if (expression.charAt(p) == ',') {
100         option(expression, p + 1);
101       } else {
102         throw new BuilderException("Parsing error in {" + new String(expression) + "} in position " + p);
103       }
104     }
105   }
106 
107   private void jdbcType(String expression, int p) {
108     int left = skipWS(expression, p);
109     int right = skipUntil(expression, left, ",");
110     if (right > left) {
111       put("jdbcType", trimmedStr(expression, left, right));
112     } else {
113       throw new BuilderException("Parsing error in {" + new String(expression) + "} in position " + p);
114     }
115     option(expression, right + 1);
116   }
117 
118   private void option(String expression, int p) {
119     int left = skipWS(expression, p);
120     if (left < expression.length()) {
121       int right = skipUntil(expression, left, "=");
122       String name = trimmedStr(expression, left, right);
123       left = right + 1;
124       right = skipUntil(expression, left, ",");
125       String value = trimmedStr(expression, left, right);
126       put(name, value);
127       option(expression, right + 1);
128     }
129   }
130 
131   private String trimmedStr(String str, int start, int end) {
132     while (str.charAt(start) <= 0x20) {
133       start++;
134     }
135     while (str.charAt(end - 1) <= 0x20) {
136       end--;
137     }
138     return start >= end ? "" : str.substring(start, end);
139   }
140 
141 }