15
15
*/
16
16
package org .apache .ibatis .builder ;
17
17
18
+ import java .lang .reflect .Type ;
19
+ import java .sql .ResultSet ;
18
20
import java .util .List ;
19
21
import java .util .Map ;
22
+ import java .util .Map .Entry ;
20
23
24
+ import org .apache .ibatis .binding .MapperMethod .ParamMap ;
21
25
import org .apache .ibatis .mapping .ParameterMapping ;
22
26
import org .apache .ibatis .mapping .ParameterMode ;
23
27
import org .apache .ibatis .parsing .TokenHandler ;
24
28
import org .apache .ibatis .reflection .MetaClass ;
25
29
import org .apache .ibatis .reflection .MetaObject ;
30
+ import org .apache .ibatis .reflection .ParamNameResolver ;
26
31
import org .apache .ibatis .reflection .property .PropertyTokenizer ;
27
32
import org .apache .ibatis .session .Configuration ;
28
33
import org .apache .ibatis .type .JdbcType ;
34
+ import org .apache .ibatis .type .TypeHandler ;
29
35
30
36
public class ParameterMappingTokenHandler extends BaseBuilder implements TokenHandler {
31
37
@@ -35,26 +41,33 @@ public class ParameterMappingTokenHandler extends BaseBuilder implements TokenHa
35
41
private final MetaObject metaParameters ;
36
42
private final Object parameterObject ;
37
43
private final boolean paramExists ;
44
+ private final ParamNameResolver paramNameResolver ;
45
+
46
+ private Type genericType = null ;
47
+ private TypeHandler <?> typeHandler = null ;
38
48
39
49
public ParameterMappingTokenHandler (List <ParameterMapping > parameterMappings , Configuration configuration ,
40
- Object parameterObject , Class <?> parameterType , Map <String , Object > additionalParameters , boolean paramExists ) {
50
+ Object parameterObject , Class <?> parameterType , Map <String , Object > additionalParameters ,
51
+ ParamNameResolver paramNameResolver , boolean paramExists ) {
41
52
super (configuration );
42
53
this .parameterType = parameterObject == null ? (parameterType == null ? Object .class : parameterType )
43
54
: parameterObject .getClass ();
44
55
this .metaParameters = configuration .newMetaObject (additionalParameters );
45
56
this .parameterObject = parameterObject ;
46
57
this .paramExists = paramExists ;
47
58
this .parameterMappings = parameterMappings ;
59
+ this .paramNameResolver = paramNameResolver ;
48
60
}
49
61
50
62
public ParameterMappingTokenHandler (List <ParameterMapping > parameterMappings , Configuration configuration ,
51
- Class <?> parameterType , Map <String , Object > additionalParameters ) {
63
+ Class <?> parameterType , Map <String , Object > additionalParameters , ParamNameResolver paramNameResolver ) {
52
64
super (configuration );
53
65
this .parameterType = parameterType ;
54
66
this .metaParameters = configuration .newMetaObject (additionalParameters );
55
67
this .parameterObject = null ;
56
68
this .paramExists = false ;
57
69
this .parameterMappings = parameterMappings ;
70
+ this .paramNameResolver = paramNameResolver ;
58
71
}
59
72
60
73
public List <ParameterMapping > getParameterMappings () {
@@ -69,60 +82,44 @@ public String handleToken(String content) {
69
82
70
83
private ParameterMapping buildParameterMapping (String content ) {
71
84
Map <String , String > propertiesMap = parseParameterMapping (content );
72
- String property = propertiesMap .get ("property" );
85
+
86
+ final String property = propertiesMap .remove ("property" );
87
+ final JdbcType jdbcType = resolveJdbcType (propertiesMap .remove ("jdbcType" ));
88
+ final String typeHandlerAlias = propertiesMap .remove ("typeHandler" );
89
+
90
+ ParameterMapping .Builder builder = new ParameterMapping .Builder (configuration , property , (Class <?>) null );
73
91
PropertyTokenizer propertyTokenizer = new PropertyTokenizer (property );
74
- Class <?> propertyType ;
75
- if (metaParameters .hasGetter (propertyTokenizer .getName ())) { // issue #448 get type from additional params
76
- propertyType = metaParameters .getGetterType (property );
77
- } else if (typeHandlerRegistry .hasTypeHandler (parameterType )) {
78
- propertyType = parameterType ;
79
- } else if (JdbcType .CURSOR .name ().equals (propertiesMap .get ("jdbcType" ))) {
80
- propertyType = java .sql .ResultSet .class ;
81
- } else if (property == null || Map .class .isAssignableFrom (parameterType )) {
82
- propertyType = Object .class ;
83
- } else {
84
- MetaClass metaClass = MetaClass .forClass (parameterType , configuration .getReflectorFactory ());
85
- if (metaClass .hasGetter (property )) {
86
- propertyType = metaClass .getGetterType (property );
87
- } else {
88
- propertyType = Object .class ;
89
- }
92
+ builder .jdbcType (jdbcType );
93
+ final Class <?> javaType = figureOutJavaType (propertiesMap , property , propertyTokenizer , jdbcType );
94
+ builder .javaType (javaType );
95
+ if (genericType == null ) {
96
+ genericType = javaType ;
97
+ }
98
+ if ((typeHandler == null || typeHandlerAlias != null ) && genericType != null && genericType != Object .class ) {
99
+ typeHandler = resolveTypeHandler (parameterType , genericType , jdbcType , typeHandlerAlias );
90
100
}
91
- ParameterMapping .Builder builder = new ParameterMapping .Builder (configuration , property , propertyType );
92
- Class <?> javaType = propertyType ;
93
- String typeHandlerAlias = null ;
101
+ builder .typeHandler (typeHandler );
102
+
94
103
ParameterMode mode = null ;
95
104
for (Map .Entry <String , String > entry : propertiesMap .entrySet ()) {
96
105
String name = entry .getKey ();
97
106
String value = entry .getValue ();
98
- if ("javaType" .equals (name )) {
99
- javaType = resolveClass (value );
100
- builder .javaType (javaType );
101
- } else if ("jdbcType" .equals (name )) {
102
- builder .jdbcType (resolveJdbcType (value ));
103
- } else if ("mode" .equals (name )) {
107
+ if ("mode" .equals (name )) {
104
108
mode = resolveParameterMode (value );
105
109
builder .mode (mode );
106
110
} else if ("numericScale" .equals (name )) {
107
111
builder .numericScale (Integer .valueOf (value ));
108
112
} else if ("resultMap" .equals (name )) {
109
113
builder .resultMapId (value );
110
- } else if ("typeHandler" .equals (name )) {
111
- typeHandlerAlias = value ;
112
114
} else if ("jdbcTypeName" .equals (name )) {
113
115
builder .jdbcTypeName (value );
114
- } else if ("property" .equals (name )) {
115
- // Do Nothing
116
116
} else if ("expression" .equals (name )) {
117
117
throw new BuilderException ("Expression based parameters are not supported yet" );
118
118
} else {
119
119
throw new BuilderException ("An invalid property '" + name + "' was found in mapping #{" + content
120
120
+ "}. Valid properties are " + PARAMETER_PROPERTIES );
121
121
}
122
122
}
123
- if (typeHandlerAlias != null ) {
124
- builder .typeHandler (resolveTypeHandler (javaType , typeHandlerAlias ));
125
- }
126
123
if (!ParameterMode .OUT .equals (mode ) && paramExists ) {
127
124
if (metaParameters .hasGetter (propertyTokenizer .getName ())) {
128
125
builder .value (metaParameters .getValue (property ));
@@ -138,6 +135,52 @@ private ParameterMapping buildParameterMapping(String content) {
138
135
return builder .build ();
139
136
}
140
137
138
+ private Class <?> figureOutJavaType (Map <String , String > propertiesMap , String property ,
139
+ PropertyTokenizer propertyTokenizer , JdbcType jdbcType ) {
140
+ Class <?> javaType = resolveClass (propertiesMap .remove ("javaType" ));
141
+ if (javaType != null ) {
142
+ return javaType ;
143
+ }
144
+ if (metaParameters .hasGetter (propertyTokenizer .getName ())) { // issue #448 get type from additional params
145
+ return metaParameters .getGetterType (property );
146
+ }
147
+ typeHandler = resolveTypeHandler (parameterType , jdbcType , (Class <? extends TypeHandler <?>>) null );
148
+ if (typeHandler != null ) {
149
+ return parameterType ;
150
+ }
151
+ if (JdbcType .CURSOR .equals (jdbcType )) {
152
+ return ResultSet .class ;
153
+ }
154
+ if (paramNameResolver != null && ParamMap .class .equals (parameterType )) {
155
+ Type actualParamType = paramNameResolver .getType (property );
156
+ if (actualParamType instanceof Type ) {
157
+ MetaClass metaClass = MetaClass .forClass (actualParamType , configuration .getReflectorFactory ());
158
+ String multiParamsPropertyName ;
159
+ if (propertyTokenizer .hasNext ()) {
160
+ multiParamsPropertyName = propertyTokenizer .getChildren ();
161
+ if (metaClass .hasGetter (multiParamsPropertyName )) {
162
+ Entry <Type , Class <?>> getterType = metaClass .getGenericGetterType (multiParamsPropertyName );
163
+ genericType = getterType .getKey ();
164
+ return getterType .getValue ();
165
+ }
166
+ } else {
167
+ genericType = actualParamType ;
168
+ }
169
+ }
170
+ return Object .class ;
171
+ }
172
+ if (Map .class .isAssignableFrom (parameterType )) {
173
+ return Object .class ;
174
+ }
175
+ MetaClass metaClass = MetaClass .forClass (parameterType , configuration .getReflectorFactory ());
176
+ if (metaClass .hasGetter (property )) {
177
+ Entry <Type , Class <?>> getterType = metaClass .getGenericGetterType (property );
178
+ genericType = getterType .getKey ();
179
+ return getterType .getValue ();
180
+ }
181
+ return Object .class ;
182
+ }
183
+
141
184
private Map <String , String > parseParameterMapping (String content ) {
142
185
try {
143
186
return new ParameterExpression (content );
0 commit comments