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

mybatis / mybatis-3 / 2694

11 Feb 2025 08:40PM UTC coverage: 87.217%. Remained the same
2694

Pull #3379

github

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

3824 of 4643 branches covered (82.36%)

526 of 589 new or added lines in 42 files covered. (89.3%)

16 existing lines in 5 files now uncovered.

9886 of 11335 relevant lines covered (87.22%)

0.87 hits per line

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

84.54
/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
            if (typeHandler == null) {
1✔
110
              typeHandler = typeHandlerRegistry.resolve(value.getClass(), null, actualJdbcType, null);
1✔
111
            }
112
          } else if (parameterObject == null) {
1✔
113
            value = null;
1✔
114
          } else {
115
            Class<? extends Object> parameterClass = parameterObject.getClass();
1✔
116
            TypeHandler paramTypeHandler = typeHandlerRegistry.getTypeHandler(parameterClass, actualJdbcType);
1✔
117
            if (paramTypeHandler != null) {
1✔
118
              value = parameterObject;
1✔
119
              typeHandler = paramTypeHandler;
1✔
120
            } else {
121
              paramMetaObject = getParamMetaObject();
1✔
122
              value = paramMetaObject.getValue(propertyName);
1✔
123
              if (typeHandler == null && value != null) {
1✔
124
                if (paramNameResolver != null && ParamMap.class.equals(parameterClass)) {
1✔
125
                  Type actualParamType = paramNameResolver.getType(propertyName);
1✔
126
                  if (actualParamType instanceof Class) {
1✔
127
                    Class<?> actualParamClass = (Class<?>) actualParamType;
1✔
128
                    MetaClass metaClass = metaClassCache.computeIfAbsent(actualParamClass,
1✔
129
                        k -> MetaClass.forClass(k, configuration.getReflectorFactory()));
1✔
130
                    PropertyTokenizer propertyTokenizer = new PropertyTokenizer(propertyName);
1✔
131
                    String multiParamsPropertyName;
132
                    if (propertyTokenizer.hasNext()) {
1✔
133
                      multiParamsPropertyName = propertyTokenizer.getChildren();
1✔
134
                      if (metaClass.hasGetter(multiParamsPropertyName)) {
1!
135
                        Entry<Type, Class<?>> getterType = metaClass.getGenericGetterType(multiParamsPropertyName);
1✔
136
                        propertyGenericType = getterType.getKey();
1✔
137
                      }
1✔
138
                    } else {
139
                      propertyGenericType = actualParamClass;
1✔
140
                    }
141
                  } else {
1✔
142
                    propertyGenericType = actualParamType;
1✔
143
                  }
144
                } else {
1✔
145
                  try {
146
                    propertyGenericType = paramMetaObject.getGenericGetterType(propertyName).getKey();
1✔
147
                    typeHandler = configuration.getTypeHandlerRegistry().resolve(parameterClass, propertyGenericType,
1✔
148
                        actualJdbcType, null);
149
                  } catch (Exception e) {
1✔
150
                    // Not always resolvable
151
                  }
1✔
152
                }
153
              }
154
            }
155
          }
156
          if (value == null) {
1✔
157
            if (jdbcType == null) {
1✔
158
              jdbcType = configuration.getJdbcTypeForNull();
1✔
159
            }
160
            if (typeHandler == null) {
1✔
161
              typeHandler = ObjectTypeHandler.INSTANCE;
1✔
162
            }
163
          } else if (typeHandler == null) {
1✔
164
            if (propertyGenericType == null) {
1✔
165
              propertyGenericType = value.getClass();
1✔
166
            }
167
            typeHandler = typeHandlerRegistry.resolve(parameterObject.getClass(), propertyGenericType, actualJdbcType,
1✔
168
                null);
169
          }
170
          if (typeHandler == null) {
1✔
171
            typeHandler = typeHandlerRegistry.getTypeHandler(actualJdbcType);
1✔
172
          }
173
          try {
174
            typeHandler.setParameter(ps, i + 1, value, jdbcType);
1✔
175
          } catch (TypeException | SQLException e) {
1✔
176
            throw new TypeException("Could not set parameters for mapping: " + parameterMapping + ". Cause: " + e, e);
1✔
177
          }
1✔
178
        }
179
      }
180
    }
181
  }
1✔
182

183
  private MetaObject getParamMetaObject() {
184
    if (paramMetaObject != null) {
1✔
185
      return paramMetaObject;
1✔
186
    }
187
    paramMetaObject = configuration.newMetaObject(parameterObject);
1✔
188
    return paramMetaObject;
1✔
189
  }
190

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

205
}
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