baomidou/mybatis-plus · error · MybatisPlusException

Unable to get MybatisMapperProxy : {}

Error message

Unable to get MybatisMapperProxy : {}

What it means

MybatisUtils.getMybatisMapperProxy(mapper) unwraps a mapper object down to the underlying MybatisMapperProxy (the JDK dynamic-proxy invocation target mybatis-plus generates). After stripping enhancement layers via extractMapperProxy, if the result is not a MybatisMapperProxy it throws MybatisPlusException('Unable to get MybatisMapperProxy : <mapper>'). This means the object passed in is not a mapper produced by a mybatis-plus SqlSessionFactory.

Source

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

        }
        SqlSessionFactory sqlSessionFactory = GlobalConfigUtils.getGlobalConfig(sqlSession.getConfiguration()).getSqlSessionFactory();
        Assert.isTrue(sqlSessionFactory != null, "Please implement access to the sqlSessionFactory property or bind sqlSessionFactory to global access.");
        return sqlSessionFactory;
    }

    /**
     * 获取代理实现
     *
     * @param mapper mapper类
     * @return 代理实现
     * @since 3.5.7
     */
    public static MybatisMapperProxy<?> getMybatisMapperProxy(Object mapper) {
        Object result = extractMapperProxy(mapper);
        if (result instanceof MybatisMapperProxy) {
            return (MybatisMapperProxy<?>) result;
        }
        throw new MybatisPlusException("Unable to get MybatisMapperProxy : " + mapper);
    }

    /**
     * 提取MapperProxy
     *
     * @param mapper Mapper对象
     * @return 真实Mapper对象(去除动态代理增强)
     * @since 3.5.12
     */
    public static Object extractMapperProxy(Object mapper) {
        if (mapper instanceof MybatisMapperProxy) {
            // fast return
            return mapper;
        }
        Object result = mapper;
        if (CompatibleHelper.hasCompatibleSet()) {
            Object proxyTargetObject = CompatibleHelper.getCompatibleSet().getProxyTargetObject(result);
            if (proxyTargetObject != null) {

View on GitHub (pinned to bf67d90747)

Solutions

  1. Verify the object actually came from a mybatis-plus SqlSessionFactory (getMapper on a MybatisSqlSessionFactoryBean-built factory).
  2. In tests, inject a real mapper (e.g. @MybatisPlusTest / spring test slice) instead of a Mockito mock when the code path calls getMybatisMapperProxy.
  3. Unwrap outer AOP/aspect layers first — extractMapperProxy can only strip layers it recognizes; keep your own unwrapping for exotic proxies.
  4. Defensively check with instanceof MybatisMapperProxy before calling if the mapper provenance is uncertain.

Example fix

// before
MybatisMapperProxy<?> proxy = MybatisUtils.getMybatisMapperProxy(maybeMock); // throws in unit tests

// after
Object raw = MybatisUtils.extractMapperProxy(maybeMock);
if (raw instanceof MybatisMapperProxy) {
    MybatisMapperProxy<?> proxy = (MybatisMapperProxy<?>) raw;
    // ...
} else {
    throw new IllegalStateException("not a mybatis-plus mapper: " + maybeMock);
}
Defensive patterns

Strategy: type-guard

Validate before calling

Object raw = MybatisUtils.extractMapperProxy(mapper);
if (!(raw instanceof MybatisMapperProxy)) {
    throw new IllegalStateException("Not a mybatis-plus mapper: " + mapper.getClass());
}

Type guard

static boolean isMybatisPlusMapper(Object o) {
    if (o == null) return false;
    if (o instanceof MybatisMapperProxy) return true;
    if (Proxy.isProxyClass(o.getClass())) {
        return Proxy.getInvocationHandler(o) instanceof MybatisMapperProxy;
    }
    return MybatisUtils.extractMapperProxy(o) instanceof MybatisMapperProxy;
}

Try / catch

try {
    MybatisMapperProxy<?> p = MybatisUtils.getMybatisMapperProxy(mapper);
} catch (MybatisPlusException e) {
    throw new IllegalStateException("Expected a mapper obtained from a mybatis-plus SqlSessionFactory", e);
}

Prevention

When it happens

Trigger: Passing a non-mapper object, a plain MyBatis (non-plus) mapper proxy, or a mock/stub to getMybatisMapperProxy; also calling it before the mapper has been created through mybatis-plus's configuration, or on a bean wrapped by AOP proxies whose invocation handler chain does not terminate in a MybatisMapperProxy.

Common situations: Mockito mocks injected where a real mapper is expected in a service test; mixing stock mybatis and mybatis-plus on the same classpath so some mappers are plain org.apache.ibatis proxies; customlazy-enhancement proxies that hide the underlying invocation handler.

Related errors


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