baomidou/mybatis-plus · error · TypeException

Failed invoking constructor for handler {}

Error message

Failed invoking constructor for handler {}

What it means

MybatisUtils' type-handler factory instantiates an IJsonTypeHandler. It first tries the constructor (Class, Field); if no Field is available it falls back to the (Class) constructor. If that reflective instantiation throws (wrong constructor signature, abstract class, inaccessible constructor, or constructor itself failing), it is wrapped in a MyBatis TypeException: 'Failed invoking constructor for handler <type>'.

Source

Thrown at mybatis-plus-core/src/main/java/com/baomidou/mybatisplus/core/toolkit/MybatisUtils.java:97

     * @param javaTypeClass java类型信息
     * @param field         属性字段
     * @return 实例化类型处理器
     */
    public static TypeHandler<?> newJsonTypeHandler(Class<? extends TypeHandler<?>> typeHandler, Class<?> javaTypeClass, Field field) {
        TypeHandler<?> result = null;
        if (IJsonTypeHandler.class.isAssignableFrom(typeHandler)) {
            if (field != null) {
                try {
                    result = typeHandler.getConstructor(Class.class, Field.class).newInstance(javaTypeClass, field);
                } catch (ReflectiveOperationException e) {
                    // ignore
                }
            }
            if (result == null) {
                try {
                    result = typeHandler.getConstructor(Class.class).newInstance(javaTypeClass);
                } catch (ReflectiveOperationException ex) {
                    throw new TypeException("Failed invoking constructor for handler " + typeHandler, ex);
                }
            }
        }
        return result;
    }

    /**
     * 获取SqlSessionFactory
     * <p>当自定义实现{@link SqlSession}时,请实现对{@link SqlSessionFactory}的访问 (spring的方式)</p>
     * <p>当无法获得{@link SqlSessionFactory}时,需要将{@link SqlSessionFactory}绑定至上下文对象中(原生mybatis访问方式)</p>
     *
     * @param mybatisMapperProxy {@link MybatisMapperProxy}
     * @return SqlSessionFactory
     * @see DefaultSqlSession
     * @see GlobalConfigUtils#getGlobalConfig(Configuration)
     * @see GlobalConfigUtils#setGlobalConfig(Configuration, GlobalConfig)
     * @since 3.5.7
     */

View on GitHub (pinned to bf67d90747)

Solutions

  1. Give the handler a public constructor accepting (Class javaType) and, for field-level instantiation, public (Class javaType, Field field).
  2. Ensure the class is concrete (not abstract/interface) and the constructors are public.
  3. If the constructor body throws, check its cause chain (ex) — commonly a missing JSON dependency (jackson-databank / fastjson) that must be added to the classpath.
  4. Verify the javaType class passed in is loadable and non-null in the type handler registration.

Example fix

// before: incompatible constructor -> TypeException
public class JsonTypeHandler extends BaseTypeHandler<MyBean> {
    public JsonTypeHandler(Field field) { ... }
}

// after: provide the expected (Class) constructor (and optionally (Class, Field))
public class JsonTypeHandler extends BaseTypeHandler<MyBean> {
    public JsonTypeHandler(Class<?> type) {
        super();
        this.type = Objects.requireNonNull(type);
    }
    public JsonTypeHandler(Class<?> type, Field field) {
        this(type);
        this.field = field;
    }
}
Defensive patterns

Strategy: validation

Validate before calling

Class<? extends TypeHandler<?>> h = MyHandler.class;
boolean hasClassCtor = false;
for (Constructor<?> c : h.getConstructors()) {
    Class<?>[] p = c.getParameterTypes();
    if (p.length == 1 && p[0] == Class.class) hasClassCtor = true;
}
if (!hasClassCtor) throw new IllegalStateException(h + " needs a public (Class) constructor");

Type guard

static boolean isInstantiableJsonHandler(Class<?> t) {
    return IJsonTypeHandler.class.isAssignableFrom(t)
        && !t.isInterface() && !java.lang.reflect.Modifier.isAbstract(t.getModifiers());
}

Try / catch

try {
    TypeHandler<?> th = newGeneratorInstance(handlerClass, javaType);
} catch (TypeException e) {
    throw new IllegalStateException("Handler " + handlerClass.getName()
        + " must expose public (Class[, Field]) constructors; root cause: " + e.getCause(), e);
}

Prevention

When it happens

Trigger: Configuring a custom type handler implementing IJsonTypeHandler whose only constructors do not match (Class, Field) or (Class) — e.g. one that takes only a Field, takes (Class, String), or has only a no-arg constructor with a non-public modifier. It also fires when the matched constructor exists but throws (missing JSON library on classpath, null javaType).

Common situations: Upgrading mybatis-plus versions where the expected handler constructor shape changed; writing a Jackson/Fastjson type handler with a non-standard constructor; deploying a custom handler whose constructor calls a dependency that is not wired.

Related errors


AI-assisted analysis of baomidou/mybatis-plus@bf67d90747 (2026-08-14). Data as JSON: /api/errors/ec82747b9c073e57. Report an issue: GitHub.