mybatis/mybatis-3 · error · TypeException
Unable to find a usable constructor for {}
Error message
Unable to find a usable constructor for {} What it means
TypeHandlerRegistry.getInstance looks for a public constructor taking java.lang.reflect.Type (or Class) and, failing that, a public no-arg constructor. If the handler class has neither, the NoSuchMethodException is wrapped in this TypeException: the handler cannot be instantiated for a mapped type.
Source
Thrown at src/main/java/org/apache/ibatis/type/TypeHandlerRegistry.java:531
if (javaType != null) {
try {
c = handlerClass.getConstructor(Type.class);
return (TypeHandler<T>) c.newInstance(javaType);
} catch (NoSuchMethodException ignored) {
}
if (javaType instanceof Class) {
try {
c = handlerClass.getConstructor(Class.class);
return (TypeHandler<T>) c.newInstance(javaType);
} catch (NoSuchMethodException ignored) {
}
}
}
try {
c = handlerClass.getConstructor();
return (TypeHandler<T>) c.newInstance();
} catch (NoSuchMethodException e) {
throw new TypeException("Unable to find a usable constructor for " + handlerClass, e);
}
} catch (ReflectiveOperationException e) {
throw new TypeException("Failed to invoke constructor for handler " + handlerClass, e);
}
}
// scan
public void register(String packageName) {
ResolverUtil<Class<?>> resolverUtil = new ResolverUtil<>();
resolverUtil.find(new ResolverUtil.IsA(TypeHandler.class), packageName);
Set<Class<? extends Class<?>>> handlerSet = resolverUtil.getClasses();
for (Class<?> type : handlerSet) {
// Ignore inner classes and interfaces (including package-info.java) and abstract classes
if (!type.isAnonymousClass() && !type.isInterface() && !Modifier.isAbstract(type.getModifiers())) {
register(type);
}
}View on GitHub (pinned to 008069adb1)
Solutions
- Add a public no-arg constructor to the handler class
- Or add a public constructor accepting a single Class/Type argument
- Reference the concrete (non-abstract, static) handler class from the mapper/configuration
Example fix
// before
public class MyHandler extends BaseTypeHandler<Json> {
private MyHandler(String cfg) { ... }
}
// after
public class MyHandler extends BaseTypeHandler<Json> {
public MyHandler() { this("default"); }
private MyHandler(String cfg) { ... }
} Defensive patterns
Strategy: validation
Validate before calling
boolean hasUsableCtor = Arrays.stream(handlerClass.getConstructors()).anyMatch( c -> c.getParameterCount() == 0 || (c.getParameterCount() == 1 && (Type.class.equals(c.getParameterTypes()[0]) || Class.class.equals(c.getParameterTypes()[0])))); if (!hasUsableCtor) throw new IllegalStateException(handlerClass + " needs a public () or (Class) constructor");
Prevention
- Standardize custom handlers on: public no-arg ctor plus optional public (Class) ctor
- Avoid constructor injection in handlers; inject configuration lazily
When it happens
Trigger: A custom handler whose only constructors take other arguments (e.g. MyHandler(String)) or are private; a handler with only a (Class) constructor that is not public; abstract handlers accidentally referenced from a mapper.
Common situations: DI-oriented handler classes designed for container injection (no usable plain constructor); inner non-static handler classes; mapper XML referencing an abstract base handler instead of the concrete subclass.
Related errors
- There is no default constructor for {}
- Error instantiating {} with invalid types ({}) or values ({}
- Failed to invoke constructor {}
- Failed to invoke constructor for handler {}
- Error creating instance. Cause: {cause}
AI-assisted analysis of mybatis/mybatis-3@008069adb1 (2026-08-14).
Data as JSON: /api/errors/4d8a567197c985c4.
Report an issue: GitHub.