mybatis/mybatis-3 · critical · IllegalStateException

There is no 'privateLookupIn(Class, Lookup)' method in java.

Error message

There is no 'privateLookupIn(Class, Lookup)' method in java.lang.invoke.MethodHandles.

What it means

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).

Source

Thrown at src/main/java/org/apache/ibatis/binding/MapperProxy.java:53

public class MapperProxy<T> implements InvocationHandler, Serializable {

  private static final long serialVersionUID = -4724728412955527868L;
  private static final Method privateLookupInMethod;
  private final SqlSession sqlSession;
  private final Class<T> mapperInterface;
  private final Map<Method, MapperMethodInvoker> methodCache;

  public MapperProxy(SqlSession sqlSession, Class<T> mapperInterface, Map<Method, MapperMethodInvoker> methodCache) {
    this.sqlSession = sqlSession;
    this.mapperInterface = mapperInterface;
    this.methodCache = methodCache;
  }

  static {
    try {
      privateLookupInMethod = MethodHandles.class.getMethod("privateLookupIn", Class.class, MethodHandles.Lookup.class);
    } catch (NoSuchMethodException e) {
      throw new IllegalStateException(
          "There is no 'privateLookupIn(Class, Lookup)' method in java.lang.invoke.MethodHandles.", e);
    }
  }

  @Override
  public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
    try {
      if (Object.class.equals(method.getDeclaringClass())) {
        return method.invoke(this, args);
      }
      return cachedInvoker(method).invoke(proxy, method, args, sqlSession);
    } catch (Throwable t) {
      throw ExceptionUtil.unwrapThrowable(t);
    }
  }

  private MapperMethodInvoker cachedInvoker(Method method) throws Throwable {
    try {

View on GitHub (pinned to 008069adb1)

Solutions

  1. Upgrade the runtime to Java 9 or newer (the supported JDK for modern MyBatis)
  2. Or downgrade MyBatis to a version matching your JVM (e.g. 3.4.x line for Java 8)
  3. Verify no classpath shadowing puts an old mybatis jar in front of the intended one

Example fix

# before
FROM openjdk:8-jre
# after
FROM openjdk:17-jre
Defensive patterns

Strategy: validation

Validate before calling

if (!System.getProperty("java.version").matches("(9|[1-9][0-9]).*")) {
  throw new IllegalStateException("MyBatis 3.5.6+ requires Java 9+");
}

Prevention

When it happens

Trigger: 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).

Common situations: 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.

Related errors


AI-assisted analysis of mybatis/mybatis-3@008069adb1 (2026-08-14). Data as JSON: /api/errors/6b28a1787f29c85d. Report an issue: GitHub.