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.annotation;
17  
18  import java.lang.reflect.Method;
19  import java.util.HashMap;
20  
21  import org.apache.ibatis.builder.BuilderException;
22  import org.apache.ibatis.builder.SqlSourceBuilder;
23  import org.apache.ibatis.mapping.BoundSql;
24  import org.apache.ibatis.mapping.SqlSource;
25  import org.apache.ibatis.session.Configuration;
26  
27  /**
28   * @author Clinton Begin
29   */
30  public class ProviderSqlSource implements SqlSource {
31  
32    private SqlSourceBuilder sqlSourceParser;
33    private Class<?> providerType;
34    private Method providerMethod;
35    private boolean providerTakesParameterObject;
36  
37    public ProviderSqlSource(Configuration config, Object provider) {
38      String providerMethodName = null;
39      try {
40        this.sqlSourceParser = new SqlSourceBuilder(config);
41        this.providerType = (Class<?>) provider.getClass().getMethod("type").invoke(provider);
42        providerMethodName = (String) provider.getClass().getMethod("method").invoke(provider);
43  
44        for (Method m : this.providerType.getMethods()) {
45          if (providerMethodName.equals(m.getName())) {
46            if (m.getParameterTypes().length < 2
47                && m.getReturnType() == String.class) {
48              this.providerMethod = m;
49              this.providerTakesParameterObject = m.getParameterTypes().length == 1;
50            }
51          }
52        }
53      } catch (Exception e) {
54        throw new BuilderException("Error creating SqlSource for SqlProvider.  Cause: " + e, e);
55      }
56      if (this.providerMethod == null) {
57        throw new BuilderException("Error creating SqlSource for SqlProvider. Method '"
58            + providerMethodName + "' not found in SqlProvider '" + this.providerType.getName() + "'.");
59      }
60    }
61  
62    @Override
63    public BoundSql getBoundSql(Object parameterObject) {
64      SqlSource sqlSource = createSqlSource(parameterObject);
65      return sqlSource.getBoundSql(parameterObject);
66    }
67  
68    private SqlSource createSqlSource(Object parameterObject) {
69      try {
70        String sql;
71        if (providerTakesParameterObject) {
72          sql = (String) providerMethod.invoke(providerType.newInstance(), parameterObject);
73        } else {
74          sql = (String) providerMethod.invoke(providerType.newInstance());
75        }
76        Class<?> parameterType = parameterObject == null ? Object.class : parameterObject.getClass();
77        return sqlSourceParser.parse(sql, parameterType, new HashMap<String, Object>());
78      } catch (Exception e) {
79        throw new BuilderException("Error invoking SqlProvider method ("
80            + providerType.getName() + "." + providerMethod.getName()
81            + ").  Cause: " + e, e);
82      }
83    }
84  
85  }