{"record":{"id":"da747a99971ad3f0","repo":"baomidou/mybatis-plus","slug":"unable-to-retrieve-the-mapperinterface-and-sqlsess","errorCode":null,"errorMessage":"Unable to retrieve the mapperInterface and sqlSession properties from %s","messagePattern":"Unable to retrieve the mapperInterface and sqlSession properties from (.+?)","errorType":"exception","errorClass":"MybatisPlusException","httpStatus":null,"severity":"error","filePath":"mybatis-plus-core/src/main/java/com/baomidou/mybatisplus/core/metadata/MapperProxyMetadata.java","lineNumber":39,"sourceCode":"\n/**\n * Mapper代理属性\n *\n * @author nieqiurong\n * @see com.baomidou.mybatisplus.core.override.MybatisMapperProxy\n * @see org.apache.ibatis.binding.MapperProxy\n * @since 3.5.12\n */\n@SuppressWarnings(\"LombokGetterMayBeUsed\")\npublic class MapperProxyMetadata {\n\n    private final SqlSession sqlSession;\n\n    private final Class<?> mapperInterface;\n\n    public MapperProxyMetadata(MetaObject metaObject) {\n        if (!metaObject.hasGetter(\"mapperInterface\") || !metaObject.hasGetter(\"sqlSession\")) {\n            throw new MybatisPlusException(\"Unable to retrieve the mapperInterface and sqlSession properties from \" + metaObject.getOriginalObject());\n        }\n        this.mapperInterface = (Class<?>) metaObject.getValue(\"mapperInterface\");\n        this.sqlSession = (SqlSession) metaObject.getValue(\"sqlSession\");\n    }\n\n    public Class<?> getMapperInterface() {\n        return mapperInterface;\n    }\n\n    public SqlSession getSqlSession() {\n        return sqlSession;\n    }\n\n    @Override\n    public String toString() {\n        return \"MapperProxy{\" +\n            \"mapperInterface=\" + mapperInterface +\n            \", sqlSession=\" + sqlSession +","sourceCodeStart":21,"sourceCodeEnd":57,"githubUrl":"https://github.com/baomidou/mybatis-plus/blob/bf67d907478c724120bf76292da54abf9e73c2b3/mybatis-plus-core/src/main/java/com/baomidou/mybatisplus/core/metadata/MapperProxyMetadata.java#L21-L57","documentation":"MapperProxyMetadata was constructed from a MetaObject that does not expose 'mapperInterface' and 'sqlSession' getters — i.e. the wrapped object is not (or cannot be reflected as) a MyBatis MapperProxy. This utility extracts the two fields every MapperProxy carries, so anything else is a programming error.","triggerScenarios":"Framework/plugin code calling new MapperProxyMetadata(SystemMetaObject.forObject(obj)) where obj is a plain bean, a JDK dynamic proxy whose handler is not MapperProxy, or a CGLIB proxy wrapping the mapper.","commonSituations":"Custom interceptors or MyBatis-Plus internals (e.g. extending the mapper proxy layer) passing the proxy object itself instead of its invocation handler; wrapping mappers in Spring AOP proxies so the reflective layout differs.","solutions":["Unwrap to the actual MapperProxy before building metadata: get the InvocationHandler of the JDK proxy first","Check metaObject.hasGetter(\"mapperInterface\") && hasGetter(\"sqlSession\") before constructing, or extract h from Proxy.getInvocationHandler(mapper) and pass that","If you wrapped mappers in another proxy layer, unwrap iteratively until the handler is a MapperProxy"],"exampleFix":"// before\nObject target = AopProxyUtils.getSingletonTarget(mapper);\nnew MapperProxyMetadata(SystemMetaObject.forObject(target)); // not a MapperProxy\n// after\nObject handler = Proxy.getInvocationHandler(mapper);\nnew MapperProxyMetadata(SystemMetaObject.forObject(handler)); // MapperProxy exposes both getters","handlingStrategy":"type-guard","validationCode":"Object h = mapper instanceof Proxy ? Proxy.getInvocationHandler(mapper) : mapper;\nif (!(h instanceof MapperProxy)) throw new IllegalArgumentException(\"Not a MyBatis mapper proxy\");","typeGuard":"static MapperProxyMetadata metadataOf(Object mapper) {\n    Object h = mapper;\n    while (h instanceof Proxy) h = Proxy.getInvocationHandler(h);\n    MetaObject mo = SystemMetaObject.forObject(h);\n    if (mo.hasGetter(\"mapperInterface\") && mo.hasGetter(\"sqlSession\")) {\n        return new MapperProxyMetadata(mo);\n    }\n    return null; // caller falls back\n}","tryCatchPattern":"catch MybatisPlusException and treat the object as non-mapper: log.debug(\"Not a MapperProxy: {}\", obj.getClass()); skip metadata extraction.","preventionTips":["Always unwrap JDK proxies to their InvocationHandler before reflecting on mapper internals","Guard with hasGetter checks (as the type-guard above) before constructing MapperProxyMetadata","Keep framework code decoupled from MapperProxy layout where a public API exists"],"tags":["mybatis","reflection","mapper-proxy","internals"],"backgroundTag":null,"analyzedSha":"bf67d907478c724120bf76292da54abf9e73c2b3","analyzedAt":"2026-08-14T15:17:09.543Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}