{"record":{"id":"f562484395637fe2","repo":"baomidou/mybatis-plus","slug":"there-is-neither-privatelookupin-class-lookup","errorCode":null,"errorMessage":"There is neither 'privateLookupIn(Class, Lookup)' nor 'Lookup(Class, int)' method in java.lang.invoke.MethodHandles.","messagePattern":"There is neither 'privateLookupIn\\(Class, Lookup\\)' nor 'Lookup\\(Class, int\\)' method in java\\.lang\\.invoke\\.MethodHandles\\.","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"critical","filePath":"mybatis-plus-core/src/main/java/com/baomidou/mybatisplus/core/override/MybatisMapperProxy.java","lineNumber":77,"sourceCode":"    }\n\n    static {\n        Method privateLookupIn;\n        try {\n            privateLookupIn = MethodHandles.class.getMethod(\"privateLookupIn\", Class.class, MethodHandles.Lookup.class);\n        } catch (NoSuchMethodException e) {\n            privateLookupIn = null;\n        }\n        privateLookupInMethod = privateLookupIn;\n\n        Constructor<MethodHandles.Lookup> lookup = null;\n        if (privateLookupInMethod == null) {\n            // JDK 1.8\n            try {\n                lookup = MethodHandles.Lookup.class.getDeclaredConstructor(Class.class, int.class);\n                lookup.setAccessible(true);\n            } catch (NoSuchMethodException e) {\n                throw new IllegalStateException(\n                    \"There is neither 'privateLookupIn(Class, Lookup)' nor 'Lookup(Class, int)' method in java.lang.invoke.MethodHandles.\",\n                    e);\n            } catch (Exception e) {\n                lookup = null;\n            }\n        }\n        lookupConstructor = lookup;\n    }\n\n    @Override\n    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {\n        try {\n            if (Object.class.equals(method.getDeclaringClass())) {\n                return method.invoke(this, args);\n            }\n            return cachedInvoker(method).invoke(proxy, method, args, sqlSession);\n        } catch (Throwable t) {\n            throw ExceptionUtil.unwrapThrowable(t);","sourceCodeStart":59,"sourceCodeEnd":95,"githubUrl":"https://github.com/baomidou/mybatis-plus/blob/bf67d907478c724120bf76292da54abf9e73c2b3/mybatis-plus-core/src/main/java/com/baomidou/mybatisplus/core/override/MybatisMapperProxy.java#L59-L95","documentation":"In a static initializer, MybatisMapperProxy tries to obtain a method handle factory: first MethodHandles.privateLookupIn (JDK 9+), and on absence falls back to the JDK 8-era MethodHandles.Lookup(Class, int) constructor. If neither is retrievable, the class cannot initialize and throws IllegalStateException. This is a JVM-compatibility failure, not an application logic error.","triggerScenarios":"Running on a non-standard or stripped JVM/runtime where both privateLookupIn is missing and the Lookup(Class,int) constructor is absent or inaccessible (some Android runtimes, restricted JVM forks, or module-lockdown setups removing the constructor via reflection filters).","commonSituations":"Deploying mybatis-plus on Android/GraalVM native images with incomplete reflection metadata; JDK builds with strong encapsulation filters (e.g. --illegal-access=deny era / later JDKs where the private constructor is filtered); ahead-of-time compilation stripping the constructor.","solutions":["Run on a standard JDK 8+ distribution (JDK 11/17 recommended) where privateLookupIn exists","For GraalVM/native-image, register MethodHandles.Lookup for reflection in reflect-config / RuntimeReflection","Upgrade mybatis-plus to a version matching your JVM; newer releases handle modern JDK encapsulation","For Android, use a JVM-compatible runtime or a mybatis alternative designed for Android"],"exampleFix":"# before: runtime lacks Lookup(Class,int) and privateLookupIn\njava --add-opens java.base/java.lang=ALL-UNNAMED -jar app.jar  # still fails if ctor filtered\n# after: use standard JDK 17 where privateLookupIn is present\njava -jar app.jar  # requires JDK 9+","handlingStrategy":"fallback","validationCode":"// At startup, verify the JVM can satisfy mapper proxy method-handle setup\ntry {\n    MethodHandles.Lookup lookup = (MethodHandles.Lookup) MethodHandles.class\n        .getMethod(\"privateLookupIn\", Class.class, MethodHandles.Lookup.class)\n        .invoke(null, MybatisMapperProxy.class, MethodHandles.lookup());\n} catch (NoSuchMethodException e) {\n    // verify JDK8 fallback constructor exists\n    MethodHandles.Lookup.class.getDeclaredConstructor(Class.class, int.class);\n}","typeGuard":null,"tryCatchPattern":"catch ExceptionInInitializerError / IllegalStateException from first mapper use; report 'unsupported runtime' to ops — no in-process retry or fallback is possible after class-init failure.","preventionTips":["Pin a standard JDK (8/11/17/21) in deployment images and CI","For native image builds, register MethodHandles.Lookup for reflection","Run a mapper smoke test in the actual target runtime as a deploy gate"],"tags":["jvm","reflection","compatibility","mybatis-plus"],"backgroundTag":null,"analyzedSha":"bf67d907478c724120bf76292da54abf9e73c2b3","analyzedAt":"2026-08-14T15:17:09.543Z","schemaVersion":2},"datasetVersion":"2026-08-15T22:17:37.221Z"}