1515 */
1616package org .apache .ibatis .builder ;
1717
18+ import java .lang .reflect .Type ;
19+ import java .sql .ResultSet ;
1820import java .util .List ;
1921import java .util .Map ;
22+ import java .util .Map .Entry ;
2023
24+ import org .apache .ibatis .binding .MapperMethod .ParamMap ;
2125import org .apache .ibatis .mapping .ParameterMapping ;
2226import org .apache .ibatis .mapping .ParameterMode ;
2327import org .apache .ibatis .parsing .TokenHandler ;
2428import org .apache .ibatis .reflection .MetaClass ;
2529import org .apache .ibatis .reflection .MetaObject ;
30+ import org .apache .ibatis .reflection .ParamNameResolver ;
2631import org .apache .ibatis .reflection .property .PropertyTokenizer ;
2732import org .apache .ibatis .session .Configuration ;
2833import org .apache .ibatis .type .JdbcType ;
34+ import org .apache .ibatis .type .TypeHandler ;
2935
3036public class ParameterMappingTokenHandler extends BaseBuilder implements TokenHandler {
3137
@@ -35,26 +41,33 @@ public class ParameterMappingTokenHandler extends BaseBuilder implements TokenHa
3541 private final MetaObject metaParameters ;
3642 private final Object parameterObject ;
3743 private final boolean paramExists ;
44+ private final ParamNameResolver paramNameResolver ;
45+
46+ private Type genericType = null ;
47+ private TypeHandler <?> typeHandler = null ;
3848
3949 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 ) {
4152 super (configuration );
4253 this .parameterType = parameterObject == null ? (parameterType == null ? Object .class : parameterType )
4354 : parameterObject .getClass ();
4455 this .metaParameters = configuration .newMetaObject (additionalParameters );
4556 this .parameterObject = parameterObject ;
4657 this .paramExists = paramExists ;
4758 this .parameterMappings = parameterMappings ;
59+ this .paramNameResolver = paramNameResolver ;
4860 }
4961
5062 public ParameterMappingTokenHandler (List <ParameterMapping > parameterMappings , Configuration configuration ,
51- Class <?> parameterType , Map <String , Object > additionalParameters ) {
63+ Class <?> parameterType , Map <String , Object > additionalParameters , ParamNameResolver paramNameResolver ) {
5264 super (configuration );
5365 this .parameterType = parameterType ;
5466 this .metaParameters = configuration .newMetaObject (additionalParameters );
5567 this .parameterObject = null ;
5668 this .paramExists = false ;
5769 this .parameterMappings = parameterMappings ;
70+ this .paramNameResolver = paramNameResolver ;
5871 }
5972
6073 public List <ParameterMapping > getParameterMappings () {
@@ -69,60 +82,44 @@ public String handleToken(String content) {
6982
7083 private ParameterMapping buildParameterMapping (String content ) {
7184 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 );
7391 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 );
90100 }
91- ParameterMapping .Builder builder = new ParameterMapping .Builder (configuration , property , propertyType );
92- Class <?> javaType = propertyType ;
93- String typeHandlerAlias = null ;
101+ builder .typeHandler (typeHandler );
102+
94103 ParameterMode mode = null ;
95104 for (Map .Entry <String , String > entry : propertiesMap .entrySet ()) {
96105 String name = entry .getKey ();
97106 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 )) {
104108 mode = resolveParameterMode (value );
105109 builder .mode (mode );
106110 } else if ("numericScale" .equals (name )) {
107111 builder .numericScale (Integer .valueOf (value ));
108112 } else if ("resultMap" .equals (name )) {
109113 builder .resultMapId (value );
110- } else if ("typeHandler" .equals (name )) {
111- typeHandlerAlias = value ;
112114 } else if ("jdbcTypeName" .equals (name )) {
113115 builder .jdbcTypeName (value );
114- } else if ("property" .equals (name )) {
115- // Do Nothing
116116 } else if ("expression" .equals (name )) {
117117 throw new BuilderException ("Expression based parameters are not supported yet" );
118118 } else {
119119 throw new BuilderException ("An invalid property '" + name + "' was found in mapping #{" + content
120120 + "}. Valid properties are " + PARAMETER_PROPERTIES );
121121 }
122122 }
123- if (typeHandlerAlias != null ) {
124- builder .typeHandler (resolveTypeHandler (javaType , typeHandlerAlias ));
125- }
126123 if (!ParameterMode .OUT .equals (mode ) && paramExists ) {
127124 if (metaParameters .hasGetter (propertyTokenizer .getName ())) {
128125 builder .value (metaParameters .getValue (property ));
@@ -138,6 +135,52 @@ private ParameterMapping buildParameterMapping(String content) {
138135 return builder .build ();
139136 }
140137
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+
141184 private Map <String , String > parseParameterMapping (String content ) {
142185 try {
143186 return new ParameterExpression (content );
0 commit comments