• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

mybatis / mybatis-3 / 2695

12 Feb 2025 06:57PM UTC coverage: 87.212% (-0.005%) from 87.217%
2695

Pull #3379

github

web-flow
Merge 1261a3400 into 12d286ea2
Pull Request #3379: Resolve type handler based on `java.lang.reflect.Type` instead of `Class` and respect runtime JDBC type

3820 of 4639 branches covered (82.35%)

525 of 591 new or added lines in 42 files covered. (88.83%)

13 existing lines in 4 files now uncovered.

9882 of 11331 relevant lines covered (87.21%)

0.87 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

84.21
/src/main/java/org/apache/ibatis/scripting/defaults/DefaultParameterHandler.java
1
/*
2
 *    Copyright 2009-2025 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.scripting.defaults;
17

18
import java.lang.reflect.Type;
19
import java.sql.ParameterMetaData;
20
import java.sql.PreparedStatement;
21
import java.sql.SQLException;
22
import java.util.HashMap;
23
import java.util.List;
24
import java.util.Map.Entry;
25

26
import org.apache.ibatis.binding.MapperMethod.ParamMap;
27
import org.apache.ibatis.executor.ErrorContext;
28
import org.apache.ibatis.executor.parameter.ParameterHandler;
29
import org.apache.ibatis.mapping.BoundSql;
30
import org.apache.ibatis.mapping.MappedStatement;
31
import org.apache.ibatis.mapping.ParameterMapping;
32
import org.apache.ibatis.mapping.ParameterMode;
33
import org.apache.ibatis.reflection.MetaClass;
34
import org.apache.ibatis.reflection.MetaObject;
35
import org.apache.ibatis.reflection.ParamNameResolver;
36
import org.apache.ibatis.reflection.property.PropertyTokenizer;
37
import org.apache.ibatis.session.Configuration;
38
import org.apache.ibatis.type.JdbcType;
39
import org.apache.ibatis.type.ObjectTypeHandler;
40
import org.apache.ibatis.type.TypeException;
41
import org.apache.ibatis.type.TypeHandler;
42
import org.apache.ibatis.type.TypeHandlerRegistry;
43

44
/**
45
 * @author Clinton Begin
46
 * @author Eduardo Macarron
47
 */
48
public class DefaultParameterHandler implements ParameterHandler {
49

50
  private final TypeHandlerRegistry typeHandlerRegistry;
51

52
  private final MappedStatement mappedStatement;
53
  private final Object parameterObject;
54
  private final BoundSql boundSql;
55
  private final Configuration configuration;
56

57
  private ParameterMetaData paramMetaData;
58
  private MetaObject paramMetaObject;
59
  private HashMap<Class<?>, MetaClass> metaClassCache = new HashMap<>();
1✔
60
  private static final ParameterMetaData NULL_PARAM_METADATA = new ParameterMetaData() {
1✔
61
    // @formatter:off
NEW
62
    public <T> T unwrap(Class<T> iface) throws SQLException { return null; }
×
NEW
63
    public boolean isWrapperFor(Class<?> iface) throws SQLException { return false; }
×
NEW
64
    public boolean isSigned(int param) throws SQLException { return false; }
×
NEW
65
    public int isNullable(int param) throws SQLException { return 0; }
×
NEW
66
    public int getScale(int param) throws SQLException { return 0; }
×
NEW
67
    public int getPrecision(int param) throws SQLException { return 0; }
×
NEW
68
    public String getParameterTypeName(int param) throws SQLException { return null; }
×
NEW
69
    public int getParameterType(int param) throws SQLException { return 0; }
×
NEW
70
    public int getParameterMode(int param) throws SQLException { return 0; }
×
NEW
71
    public int getParameterCount() throws SQLException { return 0; }
×
NEW
72
    public String getParameterClassName(int param) throws SQLException { return null; }
×
73
    // @formatter:on
74
  };
75

76
  public DefaultParameterHandler(MappedStatement mappedStatement, Object parameterObject, BoundSql boundSql) {
1✔
77
    this.mappedStatement = mappedStatement;
1✔
78
    this.configuration = mappedStatement.getConfiguration();
1✔
79
    this.typeHandlerRegistry = mappedStatement.getConfiguration().getTypeHandlerRegistry();
1✔
80
    this.parameterObject = parameterObject;
1✔
81
    this.boundSql = boundSql;
1✔
82
  }
1✔
83

84
  @Override
85
  public Object getParameterObject() {
86
    return parameterObject;
1✔
87
  }
88

89
  @SuppressWarnings({ "rawtypes", "unchecked" })
90
  @Override
91
  public void setParameters(PreparedStatement ps) {
92
    ErrorContext.instance().activity("setting parameters").object(mappedStatement.getParameterMap().getId());
1✔
93
    List<ParameterMapping> parameterMappings = boundSql.getParameterMappings();
1✔
94
    if (parameterMappings != null) {
1!
95
      ParamNameResolver paramNameResolver = mappedStatement.getParamNameResolver();
1✔
96
      for (int i = 0; i < parameterMappings.size(); i++) {
1✔
97
        ParameterMapping parameterMapping = parameterMappings.get(i);
1✔
98
        if (parameterMapping.getMode() != ParameterMode.OUT) {
1✔
99
          Object value;
100
          String propertyName = parameterMapping.getProperty();
1✔
101
          JdbcType jdbcType = parameterMapping.getJdbcType();
1✔
102
          JdbcType actualJdbcType = jdbcType == null ? getParamJdbcType(ps, i + 1) : jdbcType;
1✔
103
          Type propertyGenericType = null;
1✔
104
          TypeHandler typeHandler = parameterMapping.getTypeHandler();
1✔
105
          if (parameterMapping.hasValue()) {
1✔
106
            value = parameterMapping.getValue();
1✔
107
          } else if (boundSql.hasAdditionalParameter(propertyName)) { // issue #448 ask first for additional params
1✔
108
            value = boundSql.getAdditionalParameter(propertyName);
1✔
109
          } else if (parameterObject == null) {
1✔
110
            value = null;
1✔
111
          } else {
112
            Class<? extends Object> parameterClass = parameterObject.getClass();
1✔
113
            TypeHandler paramTypeHandler = typeHandlerRegistry.getTypeHandler(parameterClass, actualJdbcType);
1✔
114
            if (paramTypeHandler != null) {
1✔
115
              value = parameterObject;
1✔
116
              typeHandler = paramTypeHandler;
1✔
117
            } else {
118
              paramMetaObject = getParamMetaObject();
1✔
119
              value = paramMetaObject.getValue(propertyName);
1✔
120
              if (typeHandler == null && value != null) {
1✔
121
                if (paramNameResolver != null && ParamMap.class.equals(parameterClass)) {
1✔
122
                  Type actualParamType = paramNameResolver.getType(propertyName);
1✔
123
                  if (actualParamType instanceof Class) {
1✔
124
                    Class<?> actualParamClass = (Class<?>) actualParamType;
1✔
125
                    MetaClass metaClass = metaClassCache.computeIfAbsent(actualParamClass,
1✔
126
                        k -> MetaClass.forClass(k, configuration.getReflectorFactory()));
1✔
127
                    PropertyTokenizer propertyTokenizer = new PropertyTokenizer(propertyName);
1✔
128
                    String multiParamsPropertyName;
129
                    if (propertyTokenizer.hasNext()) {
1✔
130
                      multiParamsPropertyName = propertyTokenizer.getChildren();
1✔
131
                      if (metaClass.hasGetter(multiParamsPropertyName)) {
1!
132
                        Entry<Type, Class<?>> getterType = metaClass.getGenericGetterType(multiParamsPropertyName);
1✔
133
                        propertyGenericType = getterType.getKey();
1✔
134
                      }
1✔
135
                    } else {
136
                      propertyGenericType = actualParamClass;
1✔
137
                    }
138
                  } else {
1✔
139
                    propertyGenericType = actualParamType;
1✔
140
                  }
141
                } else {
1✔
142
                  try {
143
                    propertyGenericType = paramMetaObject.getGenericGetterType(propertyName).getKey();
1✔
144
                    typeHandler = configuration.getTypeHandlerRegistry().getTypeHandler(propertyGenericType,
1✔
145
                        actualJdbcType, null);
146
                  } catch (Exception e) {
1✔
147
                    // Not always resolvable
148
                  }
1✔
149
                }
150
              }
151
            }
152
          }
153
          if (value == null) {
1✔
154
            if (jdbcType == null) {
1✔
155
              jdbcType = configuration.getJdbcTypeForNull();
1✔
156
            }
157
            if (typeHandler == null) {
1✔
158
              typeHandler = ObjectTypeHandler.INSTANCE;
1✔
159
            }
160
          } else if (typeHandler == null) {
1✔
161
            if (propertyGenericType == null) {
1✔
162
              propertyGenericType = value.getClass();
1✔
163
            }
164
            typeHandler = typeHandlerRegistry.getTypeHandler(propertyGenericType, actualJdbcType, null);
1✔
165
          }
166
          if (typeHandler == null) {
1✔
167
            typeHandler = typeHandlerRegistry.getTypeHandler(actualJdbcType);
1✔
168
          }
169
          try {
170
            typeHandler.setParameter(ps, i + 1, value, jdbcType);
1✔
171
          } catch (TypeException | SQLException e) {
1✔
172
            throw new TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " + e, e);
1✔
173
          }
1✔
174
        }
175
      }
176
    }
177
  }
1✔
178

179
  private MetaObject getParamMetaObject() {
180
    if (paramMetaObject != null) {
1✔
181
      return paramMetaObject;
1✔
182
    }
183
    paramMetaObject = configuration.newMetaObject(parameterObject);
1✔
184
    return paramMetaObject;
1✔
185
  }
186

187
  private JdbcType getParamJdbcType(PreparedStatement ps, int paramIndex) {
188
    try {
189
      if (paramMetaData == null) {
1✔
190
        paramMetaData = ps.getParameterMetaData();
1✔
191
      }
192
      return paramMetaData == NULL_PARAM_METADATA ? null : JdbcType.forCode(paramMetaData.getParameterType(paramIndex));
1!
NEW
193
    } catch (SQLException e) {
×
NEW
194
      if (paramMetaData == null) {
×
NEW
195
        paramMetaData = NULL_PARAM_METADATA;
×
196
      }
NEW
197
      return null;
×
198
    }
199
  }
200

201
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc