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

mybatis / mybatis-3 / 2682

29 Jan 2025 07:08PM UTC coverage: 87.101% (-0.1%) from 87.217%
2682

Pull #3379

github

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

3812 of 4645 branches covered (82.07%)

475 of 534 new or added lines in 37 files covered. (88.95%)

26 existing lines in 5 files now uncovered.

9906 of 11373 relevant lines covered (87.1%)

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 TypeHandler<?> nullTypeHandler = new ObjectTypeHandler();
1✔
61
  private static final ParameterMetaData nullParameterMetaData = new ParameterMetaData() {
1✔
62
    // @formatter:off
NEW
63
    public <T> T unwrap(Class<T> iface) throws SQLException { return null; }
×
NEW
64
    public boolean isWrapperFor(Class<?> iface) throws SQLException { return false; }
×
NEW
65
    public boolean isSigned(int param) throws SQLException { return false; }
×
NEW
66
    public int isNullable(int param) throws SQLException { return 0; }
×
NEW
67
    public int getScale(int param) throws SQLException { return 0; }
×
NEW
68
    public int getPrecision(int param) throws SQLException { return 0; }
×
NEW
69
    public String getParameterTypeName(int param) throws SQLException { return null; }
×
NEW
70
    public int getParameterType(int param) throws SQLException { return 0; }
×
NEW
71
    public int getParameterMode(int param) throws SQLException { return 0; }
×
NEW
72
    public int getParameterCount() throws SQLException { return 0; }
×
NEW
73
    public String getParameterClassName(int param) throws SQLException { return null; }
×
74
    // @formatter:on
75
  };
76

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

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

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

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

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

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