17
17
18
18
import java .lang .reflect .Method ;
19
19
import java .util .HashMap ;
20
+ import java .util .Map ;
20
21
22
+ import org .apache .ibatis .annotations .Param ;
21
23
import org .apache .ibatis .builder .BuilderException ;
22
24
import org .apache .ibatis .builder .SqlSourceBuilder ;
23
25
import org .apache .ibatis .mapping .BoundSql ;
26
28
27
29
/**
28
30
* @author Clinton Begin
31
+ * @author Kazuki Shimizu
29
32
*/
30
33
public class ProviderSqlSource implements SqlSource {
31
34
32
35
private SqlSourceBuilder sqlSourceParser ;
33
36
private Class <?> providerType ;
34
37
private Method providerMethod ;
35
- private boolean providerTakesParameterObject ;
38
+ private String [] providerMethodArgumentNames ;
36
39
37
40
public ProviderSqlSource (Configuration config , Object provider ) {
38
41
String providerMethodName = null ;
@@ -43,13 +46,19 @@ public ProviderSqlSource(Configuration config, Object provider) {
43
46
44
47
for (Method m : this .providerType .getMethods ()) {
45
48
if (providerMethodName .equals (m .getName ())) {
46
- if (m .getParameterTypes ().length < 2
47
- && m .getReturnType () == String .class ) {
49
+ if (m .getReturnType () == String .class ) {
50
+ if (providerMethod != null ){
51
+ throw new BuilderException ("Error creating SqlSource for SqlProvider. Method '"
52
+ + providerMethodName + "' is found multiple in SqlProvider '" + this .providerType .getName ()
53
+ + "'. Sql provider method can not overload." );
54
+ }
48
55
this .providerMethod = m ;
49
- this .providerTakesParameterObject = m . getParameterTypes (). length == 1 ;
56
+ this .providerMethodArgumentNames = extractProviderMethodArgumentNames ( m ) ;
50
57
}
51
58
}
52
59
}
60
+ } catch (BuilderException e ) {
61
+ throw e ;
53
62
} catch (Exception e ) {
54
63
throw new BuilderException ("Error creating SqlSource for SqlProvider. Cause: " + e , e );
55
64
}
@@ -67,19 +76,59 @@ public BoundSql getBoundSql(Object parameterObject) {
67
76
68
77
private SqlSource createSqlSource (Object parameterObject ) {
69
78
try {
79
+ Class <?>[] parameterTypes = providerMethod .getParameterTypes ();
70
80
String sql ;
71
- if (providerTakesParameterObject ) {
81
+ if (parameterTypes .length == 0 ) {
82
+ sql = (String ) providerMethod .invoke (providerType .newInstance ());
83
+ } else if (parameterTypes .length == 1 ) {
72
84
sql = (String ) providerMethod .invoke (providerType .newInstance (), parameterObject );
85
+ } else if (parameterObject instanceof Map ) {
86
+ @ SuppressWarnings ("unchecked" )
87
+ Map <String , Object > params = (Map <String , Object >) parameterObject ;
88
+ sql = (String ) providerMethod .invoke (providerType .newInstance (), extractProviderMethodArguments (params , providerMethodArgumentNames ));
73
89
} else {
74
- sql = (String ) providerMethod .invoke (providerType .newInstance ());
90
+ throw new BuilderException ("Error invoking SqlProvider method ("
91
+ + providerType .getName () + "." + providerMethod .getName ()
92
+ + "). Cannot invoke a method that holds multiple arguments using a specifying parameterObject. In this case, please specify a 'java.util.Map' object." );
75
93
}
76
94
Class <?> parameterType = parameterObject == null ? Object .class : parameterObject .getClass ();
77
95
return sqlSourceParser .parse (sql , parameterType , new HashMap <String , Object >());
96
+ } catch (BuilderException e ) {
97
+ throw e ;
78
98
} catch (Exception e ) {
79
99
throw new BuilderException ("Error invoking SqlProvider method ("
80
100
+ providerType .getName () + "." + providerMethod .getName ()
81
101
+ "). Cause: " + e , e );
82
102
}
83
103
}
84
104
105
+ private String [] extractProviderMethodArgumentNames (Method providerMethod ) {
106
+ String [] argumentNames = new String [providerMethod .getParameterTypes ().length ];
107
+ for (int i = 0 ; i < argumentNames .length ; i ++) {
108
+ Param param = findParamAnnotation (providerMethod , i );
109
+ argumentNames [i ] = param != null ? param .value () : "param" + (i + 1 );
110
+ }
111
+ return argumentNames ;
112
+ }
113
+
114
+ private Param findParamAnnotation (Method providerMethod , int parameterIndex ) {
115
+ final Object [] annotations = providerMethod .getParameterAnnotations ()[parameterIndex ];
116
+ Param param = null ;
117
+ for (Object annotation : annotations ) {
118
+ if (annotation instanceof Param ) {
119
+ param = Param .class .cast (annotation );
120
+ break ;
121
+ }
122
+ }
123
+ return param ;
124
+ }
125
+
126
+ private Object [] extractProviderMethodArguments (Map <String , Object > params , String [] argumentNames ) {
127
+ Object [] args = new Object [argumentNames .length ];
128
+ for (int i = 0 ; i < args .length ; i ++) {
129
+ args [i ] = params .get (argumentNames [i ]);
130
+ }
131
+ return args ;
132
+ }
133
+
85
134
}
0 commit comments