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

mybatis / mybatis-3 / 2604

03 Jan 2025 10:00AM UTC coverage: 87.524% (+0.3%) from 87.177%
2604

Pull #3146

github

web-flow
Merge 60c1f5fea into 8ac3920af
Pull Request #3146: Shared ambiguity instance

3633 of 4401 branches covered (82.55%)

4 of 4 new or added lines in 1 file covered. (100.0%)

254 existing lines in 22 files now uncovered.

9569 of 10933 relevant lines covered (87.52%)

0.88 hits per line

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

92.13
/src/main/java/org/apache/ibatis/reflection/TypeParameterResolver.java
1
/*
2
 *    Copyright 2009-2024 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.reflection;
17

18
import java.lang.reflect.Array;
19
import java.lang.reflect.Field;
20
import java.lang.reflect.GenericArrayType;
21
import java.lang.reflect.Method;
22
import java.lang.reflect.ParameterizedType;
23
import java.lang.reflect.Type;
24
import java.lang.reflect.TypeVariable;
25
import java.lang.reflect.WildcardType;
26
import java.util.Arrays;
27

28
/**
29
 * @author Iwao AVE!
30
 */
31
public class TypeParameterResolver {
32

33
  /**
34
   * Resolve field type.
35
   *
36
   * @param field
37
   *          the field
38
   * @param srcType
39
   *          the src type
40
   *
41
   * @return The field type as {@link Type}. If it has type parameters in the declaration,<br>
42
   *         they will be resolved to the actual runtime {@link Type}s.
43
   */
44
  public static Type resolveFieldType(Field field, Type srcType) {
45
    Type fieldType = field.getGenericType();
1✔
46
    Class<?> declaringClass = field.getDeclaringClass();
1✔
47
    return resolveType(fieldType, srcType, declaringClass);
1✔
48
  }
49

50
  /**
51
   * Resolve return type.
52
   *
53
   * @param method
54
   *          the method
55
   * @param srcType
56
   *          the src type
57
   *
58
   * @return The return type of the method as {@link Type}. If it has type parameters in the declaration,<br>
59
   *         they will be resolved to the actual runtime {@link Type}s.
60
   */
61
  public static Type resolveReturnType(Method method, Type srcType) {
62
    Type returnType = method.getGenericReturnType();
1✔
63
    Class<?> declaringClass = method.getDeclaringClass();
1✔
64
    return resolveType(returnType, srcType, declaringClass);
1✔
65
  }
66

67
  /**
68
   * Resolve param types.
69
   *
70
   * @param method
71
   *          the method
72
   * @param srcType
73
   *          the src type
74
   *
75
   * @return The parameter types of the method as an array of {@link Type}s. If they have type parameters in the
76
   *         declaration,<br>
77
   *         they will be resolved to the actual runtime {@link Type}s.
78
   */
79
  public static Type[] resolveParamTypes(Method method, Type srcType) {
80
    Type[] paramTypes = method.getGenericParameterTypes();
1✔
81
    Class<?> declaringClass = method.getDeclaringClass();
1✔
82
    Type[] result = new Type[paramTypes.length];
1✔
83
    for (int i = 0; i < paramTypes.length; i++) {
1✔
84
      result[i] = resolveType(paramTypes[i], srcType, declaringClass);
1✔
85
    }
86
    return result;
1✔
87
  }
88

89
  private static Type resolveType(Type type, Type srcType, Class<?> declaringClass) {
90
    if (type instanceof TypeVariable) {
1✔
91
      return resolveTypeVar((TypeVariable<?>) type, srcType, declaringClass);
1✔
92
    }
93
    if (type instanceof ParameterizedType) {
1✔
94
      return resolveParameterizedType((ParameterizedType) type, srcType, declaringClass);
1✔
95
    } else if (type instanceof GenericArrayType) {
1✔
96
      return resolveGenericArrayType((GenericArrayType) type, srcType, declaringClass);
1✔
97
    } else {
98
      return type;
1✔
99
    }
100
  }
101

102
  private static Type resolveGenericArrayType(GenericArrayType genericArrayType, Type srcType,
103
      Class<?> declaringClass) {
104
    Type componentType = genericArrayType.getGenericComponentType();
1✔
105
    Type resolvedComponentType = null;
1✔
106
    if (componentType instanceof TypeVariable) {
1✔
107
      resolvedComponentType = resolveTypeVar((TypeVariable<?>) componentType, srcType, declaringClass);
1✔
108
    } else if (componentType instanceof GenericArrayType) {
1✔
109
      resolvedComponentType = resolveGenericArrayType((GenericArrayType) componentType, srcType, declaringClass);
1✔
110
    } else if (componentType instanceof ParameterizedType) {
1!
111
      resolvedComponentType = resolveParameterizedType((ParameterizedType) componentType, srcType, declaringClass);
1✔
112
    }
113
    if (resolvedComponentType instanceof Class) {
1✔
114
      return Array.newInstance((Class<?>) resolvedComponentType, 0).getClass();
1✔
115
    }
116
    return new GenericArrayTypeImpl(resolvedComponentType);
1✔
117
  }
118

119
  private static ParameterizedType resolveParameterizedType(ParameterizedType parameterizedType, Type srcType,
120
      Class<?> declaringClass) {
121
    Class<?> rawType = (Class<?>) parameterizedType.getRawType();
1✔
122
    Type[] typeArgs = parameterizedType.getActualTypeArguments();
1✔
123
    Type[] args = new Type[typeArgs.length];
1✔
124
    for (int i = 0; i < typeArgs.length; i++) {
1✔
125
      if (typeArgs[i] instanceof TypeVariable) {
1✔
126
        args[i] = resolveTypeVar((TypeVariable<?>) typeArgs[i], srcType, declaringClass);
1✔
127
      } else if (typeArgs[i] instanceof ParameterizedType) {
1✔
128
        args[i] = resolveParameterizedType((ParameterizedType) typeArgs[i], srcType, declaringClass);
1✔
129
      } else if (typeArgs[i] instanceof WildcardType) {
1✔
130
        args[i] = resolveWildcardType((WildcardType) typeArgs[i], srcType, declaringClass);
1✔
131
      } else {
132
        args[i] = typeArgs[i];
1✔
133
      }
134
    }
135
    return new ParameterizedTypeImpl(rawType, null, args);
1✔
136
  }
137

138
  private static Type resolveWildcardType(WildcardType wildcardType, Type srcType, Class<?> declaringClass) {
139
    Type[] lowerBounds = resolveWildcardTypeBounds(wildcardType.getLowerBounds(), srcType, declaringClass);
1✔
140
    Type[] upperBounds = resolveWildcardTypeBounds(wildcardType.getUpperBounds(), srcType, declaringClass);
1✔
141
    return new WildcardTypeImpl(lowerBounds, upperBounds);
1✔
142
  }
143

144
  private static Type[] resolveWildcardTypeBounds(Type[] bounds, Type srcType, Class<?> declaringClass) {
145
    Type[] result = new Type[bounds.length];
1✔
146
    for (int i = 0; i < bounds.length; i++) {
1✔
147
      if (bounds[i] instanceof TypeVariable) {
1✔
148
        result[i] = resolveTypeVar((TypeVariable<?>) bounds[i], srcType, declaringClass);
1✔
149
      } else if (bounds[i] instanceof ParameterizedType) {
1!
150
        result[i] = resolveParameterizedType((ParameterizedType) bounds[i], srcType, declaringClass);
×
151
      } else if (bounds[i] instanceof WildcardType) {
1!
152
        result[i] = resolveWildcardType((WildcardType) bounds[i], srcType, declaringClass);
×
153
      } else {
154
        result[i] = bounds[i];
1✔
155
      }
156
    }
157
    return result;
1✔
158
  }
159

160
  private static Type resolveTypeVar(TypeVariable<?> typeVar, Type srcType, Class<?> declaringClass) {
161
    Type result;
162
    Class<?> clazz;
163
    if (srcType instanceof Class) {
1✔
164
      clazz = (Class<?>) srcType;
1✔
165
    } else if (srcType instanceof ParameterizedType) {
1!
166
      ParameterizedType parameterizedType = (ParameterizedType) srcType;
1✔
167
      clazz = (Class<?>) parameterizedType.getRawType();
1✔
168
    } else {
1✔
169
      throw new IllegalArgumentException(
×
170
          "The 2nd arg must be Class or ParameterizedType, but was: " + srcType.getClass());
×
171
    }
172

173
    if (clazz == declaringClass) {
1✔
174
      Type[] bounds = typeVar.getBounds();
1✔
175
      if (bounds.length > 0) {
1!
176
        return bounds[0];
1✔
177
      }
178
      return Object.class;
×
179
    }
180

181
    Type superclass = clazz.getGenericSuperclass();
1✔
182
    result = scanSuperTypes(typeVar, srcType, declaringClass, clazz, superclass);
1✔
183
    if (result != null) {
1✔
184
      return result;
1✔
185
    }
186

187
    Type[] superInterfaces = clazz.getGenericInterfaces();
1✔
188
    for (Type superInterface : superInterfaces) {
1!
189
      result = scanSuperTypes(typeVar, srcType, declaringClass, clazz, superInterface);
1✔
190
      if (result != null) {
1!
191
        return result;
1✔
192
      }
193
    }
194
    return Object.class;
×
195
  }
196

197
  private static Type scanSuperTypes(TypeVariable<?> typeVar, Type srcType, Class<?> declaringClass, Class<?> clazz,
198
      Type superclass) {
199
    if (superclass instanceof ParameterizedType) {
1✔
200
      ParameterizedType parentAsType = (ParameterizedType) superclass;
1✔
201
      Class<?> parentAsClass = (Class<?>) parentAsType.getRawType();
1✔
202
      TypeVariable<?>[] parentTypeVars = parentAsClass.getTypeParameters();
1✔
203
      if (srcType instanceof ParameterizedType) {
1✔
204
        parentAsType = translateParentTypeVars((ParameterizedType) srcType, clazz, parentAsType);
1✔
205
      }
206
      if (declaringClass == parentAsClass) {
1✔
207
        for (int i = 0; i < parentTypeVars.length; i++) {
1✔
208
          if (typeVar.equals(parentTypeVars[i])) {
1✔
209
            Type actualType = parentAsType.getActualTypeArguments()[i];
1✔
210
            return actualType instanceof TypeVariable<?> ? Object.class : actualType;
1✔
211
          }
212
        }
213
      }
214
      if (declaringClass.isAssignableFrom(parentAsClass)) {
1!
215
        return resolveTypeVar(typeVar, parentAsType, declaringClass);
1✔
216
      }
217
    } else if (superclass instanceof Class && declaringClass.isAssignableFrom((Class<?>) superclass)) {
1!
UNCOV
218
      return resolveTypeVar(typeVar, superclass, declaringClass);
×
219
    }
220
    return null;
1✔
221
  }
222

223
  private static ParameterizedType translateParentTypeVars(ParameterizedType srcType, Class<?> srcClass,
224
      ParameterizedType parentType) {
225
    Type[] parentTypeArgs = parentType.getActualTypeArguments();
1✔
226
    Type[] srcTypeArgs = srcType.getActualTypeArguments();
1✔
227
    TypeVariable<?>[] srcTypeVars = srcClass.getTypeParameters();
1✔
228
    Type[] newParentArgs = new Type[parentTypeArgs.length];
1✔
229
    boolean noChange = true;
1✔
230
    for (int i = 0; i < parentTypeArgs.length; i++) {
1✔
231
      if (parentTypeArgs[i] instanceof TypeVariable) {
1✔
232
        for (int j = 0; j < srcTypeVars.length; j++) {
1✔
233
          if (srcTypeVars[j].equals(parentTypeArgs[i])) {
1✔
234
            noChange = false;
1✔
235
            newParentArgs[i] = srcTypeArgs[j];
1✔
236
          }
237
        }
238
      } else {
239
        newParentArgs[i] = parentTypeArgs[i];
1✔
240
      }
241
    }
242
    return noChange ? parentType : new ParameterizedTypeImpl((Class<?>) parentType.getRawType(), null, newParentArgs);
1!
243
  }
244

245
  private TypeParameterResolver() {
246
  }
247

248
  static class ParameterizedTypeImpl implements ParameterizedType {
249
    private final Class<?> rawType;
250

251
    private final Type ownerType;
252

253
    private final Type[] actualTypeArguments;
254

255
    public ParameterizedTypeImpl(Class<?> rawType, Type ownerType, Type[] actualTypeArguments) {
1✔
256
      this.rawType = rawType;
1✔
257
      this.ownerType = ownerType;
1✔
258
      this.actualTypeArguments = actualTypeArguments;
1✔
259
    }
1✔
260

261
    @Override
262
    public Type[] getActualTypeArguments() {
263
      return actualTypeArguments;
1✔
264
    }
265

266
    @Override
267
    public Type getOwnerType() {
UNCOV
268
      return ownerType;
×
269
    }
270

271
    @Override
272
    public Type getRawType() {
273
      return rawType;
1✔
274
    }
275

276
    @Override
277
    public String toString() {
278
      return "ParameterizedTypeImpl [rawType=" + rawType + ", ownerType=" + ownerType + ", actualTypeArguments="
×
UNCOV
279
          + Arrays.toString(actualTypeArguments) + "]";
×
280
    }
281
  }
282

283
  static class WildcardTypeImpl implements WildcardType {
284
    private final Type[] lowerBounds;
285

286
    private final Type[] upperBounds;
287

288
    WildcardTypeImpl(Type[] lowerBounds, Type[] upperBounds) {
1✔
289
      this.lowerBounds = lowerBounds;
1✔
290
      this.upperBounds = upperBounds;
1✔
291
    }
1✔
292

293
    @Override
294
    public Type[] getLowerBounds() {
295
      return lowerBounds;
1✔
296
    }
297

298
    @Override
299
    public Type[] getUpperBounds() {
300
      return upperBounds;
1✔
301
    }
302
  }
303

304
  static class GenericArrayTypeImpl implements GenericArrayType {
305
    private final Type genericComponentType;
306

307
    GenericArrayTypeImpl(Type genericComponentType) {
1✔
308
      this.genericComponentType = genericComponentType;
1✔
309
    }
1✔
310

311
    @Override
312
    public Type getGenericComponentType() {
313
      return genericComponentType;
1✔
314
    }
315
  }
316
}
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

© 2025 Coveralls, Inc