{"record":{"id":"6b28a1787f29c85d","repo":"mybatis/mybatis-3","slug":"there-is-no-privatelookupin-class-lookup-metho","errorCode":null,"errorMessage":"There is no 'privateLookupIn(Class, Lookup)' method in java.lang.invoke.MethodHandles.","messagePattern":"There is no 'privateLookupIn\\(Class, Lookup\\)' method in java\\.lang\\.invoke\\.MethodHandles\\.","errorType":"exception","errorClass":"IllegalStateException","httpStatus":null,"severity":"critical","filePath":"src/main/java/org/apache/ibatis/binding/MapperProxy.java","lineNumber":53,"sourceCode":"public class MapperProxy<T> implements InvocationHandler, Serializable {\n\n  private static final long serialVersionUID = -4724728412955527868L;\n  private static final Method privateLookupInMethod;\n  private final SqlSession sqlSession;\n  private final Class<T> mapperInterface;\n  private final Map<Method, MapperMethodInvoker> methodCache;\n\n  public MapperProxy(SqlSession sqlSession, Class<T> mapperInterface, Map<Method, MapperMethodInvoker> methodCache) {\n    this.sqlSession = sqlSession;\n    this.mapperInterface = mapperInterface;\n    this.methodCache = methodCache;\n  }\n\n  static {\n    try {\n      privateLookupInMethod = MethodHandles.class.getMethod(\"privateLookupIn\", Class.class, MethodHandles.Lookup.class);\n    } catch (NoSuchMethodException e) {\n      throw new IllegalStateException(\n          \"There is no 'privateLookupIn(Class, Lookup)' method in java.lang.invoke.MethodHandles.\", e);\n    }\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);\n    }\n  }\n\n  private MapperMethodInvoker cachedInvoker(Method method) throws Throwable {\n    try {","sourceCodeStart":35,"sourceCodeEnd":71,"githubUrl":"https://github.com/mybatis/mybatis-3/blob/008069adb1b089579b5dcba87ee591908b263274/src/main/java/org/apache/ibatis/binding/MapperProxy.java#L35-L71","documentation":"MapperProxy's static initializer reflectively looks up MethodHandles.privateLookupIn, which exists only since Java 9. On an older JVM the lookup fails and this IllegalStateException is thrown from the class-init block, meaning MyBatis 3.5.x requires Java 9+ (this reflects the default method invocation support for mapper interfaces with default methods).","triggerScenarios":"Running a MyBatis version that uses privateLookupIn (3.5.6+ era) on Java 8 or earlier; a build compiled for a newer JDK deployed onto an old JRE (e.g. app server with bundled Java 8).","commonSituations":"Upgrading MyBatis without upgrading the runtime; Docker images pinned to java:8-jre; legacy application servers (WebLogic/WebSphere on Java 8) with a newer mybatis jar on the classpath.","solutions":["Upgrade the runtime to Java 9 or newer (the supported JDK for modern MyBatis)","Or downgrade MyBatis to a version matching your JVM (e.g. 3.4.x line for Java 8)","Verify no classpath shadowing puts an old mybatis jar in front of the intended one"],"exampleFix":"# before\nFROM openjdk:8-jre\n# after\nFROM openjdk:17-jre","handlingStrategy":"validation","validationCode":"if (!System.getProperty(\"java.version\").matches(\"(9|[1-9][0-9]).*\")) {\n  throw new IllegalStateException(\"MyBatis 3.5.6+ requires Java 9+\");\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Pin Docker/app-server images to Java 9+ (17 recommended) before upgrading MyBatis","Add an enforcer rule (requireJavaVersion) in the build matching the runtime"],"tags":["mybatis","jvm","java-version","environment"],"backgroundTag":null,"analyzedSha":"008069adb1b089579b5dcba87ee591908b263274","analyzedAt":"2026-08-14T13:07:10.264Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}