mybatis/mybatis-3 · error · IllegalArgumentException
The 2nd arg must be Class or ParameterizedType, but was: {}
Error message
The 2nd arg must be Class or ParameterizedType, but was: {} What it means
TypeParameterResolver.resolveTypeVar requires the source type (the class the member was declared against) to be a plain Class or a ParameterizedType. Any other Type implementation — a TypeVariable, WildcardType, or GenericArrayType — is rejected with IllegalArgumentException.
Source
Thrown at src/main/java/org/apache/ibatis/reflection/TypeParameterResolver.java:161
private static Type resolveTypeVar(TypeVariable<?> typeVar, Type srcType, Class<?> declaringClass) {
Type result;
Class<?> clazz;
if (srcType instanceof Class) {
clazz = (Class<?>) srcType;
} else if (srcType instanceof ParameterizedType) {
ParameterizedType parameterizedType = (ParameterizedType) srcType;
clazz = (Class<?>) parameterizedType.getRawType();
if (clazz == declaringClass) {
TypeVariable<?>[] typeVars = declaringClass.getTypeParameters();
for (int i = 0; i < typeVars.length; i++) {
if (typeVar.equals(typeVars[i])) {
return parameterizedType.getActualTypeArguments()[i];
}
}
}
} else {
throw new IllegalArgumentException(
"The 2nd arg must be Class or ParameterizedType, but was: " + srcType.getClass());
}
if (clazz == declaringClass) {
Type[] bounds = typeVar.getBounds();
if (bounds.length > 0) {
return bounds[0];
}
return Object.class;
}
Type superclass = clazz.getGenericSuperclass();
result = scanSuperTypes(typeVar, srcType, declaringClass, clazz, superclass);
if (result != null) {
return result;
}
Type[] superInterfaces = clazz.getGenericInterfaces();View on GitHub (pinned to 008069adb1)
Solutions
- Supply concrete type arguments: class MyMapper extends BaseMapper<User> instead of raw BaseMapper.
- If you call TypeParameterResolver directly, materialize ParameterizedTypes (e.g. via TypeToken/ParameterizedTypeImpl) before passing srcType.
- Simplify the generic signature at the failing boundary so the declaring type is a Class or fully parameterized type.
Example fix
// before
class UserDao extends BaseDao { ... } // raw, T unresolved
// after
class UserDao extends BaseDao<User> { ... } Defensive patterns
Strategy: type-guard
Validate before calling
if (!(srcType instanceof Class) && !(srcType instanceof ParameterizedType)) {
throw new IllegalArgumentException("resolve srcType to Class/ParameterizedType first");
} Type guard
boolean resolvableType(Type t) {
return t instanceof Class || t instanceof ParameterizedType;
} Prevention
- Never subclass generic MyBatis base types raw; always pass concrete type arguments.
- When doing custom reflection, materialize ParameterizedType instances before delegating to TypeParameterResolver.
When it happens
Trigger: Resolving a member whose declaring 'class' is itself unresolved: e.g. subclass hierarchies where getGenericSuperclass() returns a TypeVariable or a generic array because the concrete type arguments were never supplied (raw subclass of a generic base).
Common situations: Raw types: class MyMapper extends BaseMapper without <T> argument; wildcard/generic-array boundaries in deeply generic mappers or type handlers; custom reflection tooling calling TypeParameterResolver directly with unresolved Types.
Related errors
- '" + this.getClass() + "' must override the default method '
- '" + this.getClass() + "' must override the default method '
- Error creating instance. Cause: {cause}
- Error in result map '{resultMapId}'. Failed to find a constr
- Failed to create a new Configuration instance.
AI-assisted analysis of mybatis/mybatis-3@008069adb1 (2026-08-14).
Data as JSON: /api/errors/54abe259dd852583.
Report an issue: GitHub.