View Javadoc
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.submitted.language;
17  
18  import java.util.ArrayList;
19  import java.util.List;
20  import java.util.Map;
21  
22  import org.apache.ibatis.builder.BaseBuilder;
23  import org.apache.ibatis.builder.BuilderException;
24  import org.apache.ibatis.builder.ParameterExpression;
25  import org.apache.ibatis.builder.StaticSqlSource;
26  import org.apache.ibatis.mapping.ParameterMapping;
27  import org.apache.ibatis.mapping.SqlSource;
28  import org.apache.ibatis.parsing.GenericTokenParser;
29  import org.apache.ibatis.parsing.TokenHandler;
30  import org.apache.ibatis.reflection.MetaClass;
31  import org.apache.ibatis.session.Configuration;
32  import org.apache.ibatis.type.JdbcType;
33  
34  /**
35   * Just a test case. Not a real Velocity implementation.
36   */
37  public class VelocitySqlSourceBuilder extends BaseBuilder {
38  
39    private static final String parameterProperties = "javaType,jdbcType,mode,numericScale,resultMap,typeHandler,jdbcTypeName";
40  
41    public VelocitySqlSourceBuilder(Configuration configuration) {
42      super(configuration);
43    }
44  
45    public SqlSource parse(String originalSql, Class<?> parameterType) {
46      ParameterMappingTokenHandler handler = new ParameterMappingTokenHandler(configuration, parameterType);
47      GenericTokenParser parser = new GenericTokenParser("@{", "}", handler);
48      String sql = parser.parse(originalSql);
49      return new StaticSqlSource(configuration, sql, handler.getParameterMappings());
50    }
51  
52    private static class ParameterMappingTokenHandler extends BaseBuilder implements TokenHandler {
53  
54      private final List<ParameterMapping> parameterMappings = new ArrayList<>();
55      private final Class<?> parameterType;
56  
57      public ParameterMappingTokenHandler(Configuration configuration, Class<?> parameterType) {
58        super(configuration);
59        this.parameterType = parameterType;
60      }
61  
62      public List<ParameterMapping> getParameterMappings() {
63        return parameterMappings;
64      }
65  
66      @Override
67      public String handleToken(String content) {
68        parameterMappings.add(buildParameterMapping(content));
69        return "?";
70      }
71  
72      private ParameterMapping buildParameterMapping(String content) {
73        Map<String, String> propertiesMap = parseParameterMapping(content);
74        String property = propertiesMap.get("property");
75        String jdbcType = propertiesMap.get("jdbcType");
76        Class<?> propertyType;
77        if (typeHandlerRegistry.hasTypeHandler(parameterType)) {
78          propertyType = parameterType;
79        } else if (JdbcType.CURSOR.name().equals(jdbcType)) {
80          propertyType = java.sql.ResultSet.class;
81        } else if (property != null) {
82          MetaClass metaClass = MetaClass.forClass(parameterType, configuration.getReflectorFactory());
83          if (metaClass.hasGetter(property)) {
84            propertyType = metaClass.getGetterType(property);
85          } else {
86            propertyType = Object.class;
87          }
88        } else {
89          propertyType = Object.class;
90        }
91        ParameterMapping.Builder builder = new ParameterMapping.Builder(configuration, property, propertyType);
92        if (jdbcType != null) {
93          builder.jdbcType(resolveJdbcType(jdbcType));
94        }
95        Class<?> javaType = null;
96        String typeHandlerAlias = null;
97        for (Map.Entry<String, String> entry : propertiesMap.entrySet()) {
98          String name = entry.getKey();
99          String value = entry.getValue();
100         if ("javaType".equals(name)) {
101           javaType = resolveClass(value);
102           builder.javaType(javaType);
103         } else if ("jdbcType".equals(name)) {
104           builder.jdbcType(resolveJdbcType(value));
105         } else if ("mode".equals(name)) {
106           builder.mode(resolveParameterMode(value));
107         } else if ("numericScale".equals(name)) {
108           builder.numericScale(Integer.valueOf(value));
109         } else if ("resultMap".equals(name)) {
110           builder.resultMapId(value);
111         } else if ("typeHandler".equals(name)) {
112           typeHandlerAlias = value;
113         } else if ("jdbcTypeName".equals(name)) {
114           builder.jdbcTypeName(value);
115         } else if ("property".equals(name)) {
116           // Do Nothing
117         } else if ("expression".equals(name)) {
118           builder.expression(value);
119         } else {
120           throw new BuilderException("An invalid property '" + name + "' was found in mapping @{" + content
121               + "}.  Valid properties are " + parameterProperties);
122         }
123       }
124       if (typeHandlerAlias != null) {
125         builder.typeHandler(resolveTypeHandler(javaType, typeHandlerAlias));
126       }
127       return builder.build();
128     }
129 
130     private Map<String, String> parseParameterMapping(String content) {
131       try {
132         return new ParameterExpression(content);
133       } catch (BuilderException ex) {
134         throw ex;
135       } catch (Exception ex) {
136         throw new BuilderException("Parsing error was found in mapping @{" + content
137             + "}.  Check syntax #{property|(expression), var1=value1, var2=value2, ...} ", ex);
138       }
139     }
140   }
141 
142 }