mybatis/mybatis-3 · error · ReflectionException

Failed to invoke 'Class.isRecord()'.

Error message

Failed to invoke 'Class.isRecord()'.

What it means

Reflector caches a MethodHandle for Class.isRecord() (absent on Java < 16) and invokes it via invokeExact to detect record classes. This ReflectionException means the invoke itself threw — the handle existed but the exact invocation failed, which should not happen on a standard JVM.

Source

Thrown at src/main/java/org/apache/ibatis/reflection/Reflector.java:491

   *
   * @return True if the object has a readable property by the name
   */
  public boolean hasGetter(String propertyName) {
    return getMethods.containsKey(propertyName);
  }

  public String findPropertyName(String name) {
    return caseInsensitivePropertyMap.get(name.toUpperCase(Locale.ENGLISH));
  }

  /**
   * Class.isRecord() alternative for Java 15 and older.
   */
  private static boolean isRecord(Class<?> clazz) {
    try {
      return isRecordMethodHandle != null && (boolean) isRecordMethodHandle.invokeExact(clazz);
    } catch (Throwable e) {
      throw new ReflectionException("Failed to invoke 'Class.isRecord()'.", e);
    }
  }

  private static MethodHandle getIsRecordMethodHandle() {
    MethodHandles.Lookup lookup = MethodHandles.lookup();
    MethodType mt = MethodType.methodType(boolean.class);
    try {
      return lookup.findVirtual(Class.class, "isRecord", mt);
    } catch (NoSuchMethodException | IllegalAccessException e) {
      return null;
    }
  }
}

View on GitHub (pinned to 008069adb1)

Solutions

  1. Run on a standard JDK 16+ (or any supported stock JDK) and re-test.
  2. Disable class transformers/agents that rewrite java.lang.Class or the application classes involved.
  3. If on GraalVM native-image, ensure a recent version with full MethodHandle support and proper reflection metadata registered.
Defensive patterns

Strategy: fallback

Validate before calling

if (Runtime.version().feature() >= 16 && Runtime.getPages... ) { /* placeholder */ }
// simpler: detect standard JVM before relying on record resultTypes
boolean recordsSafe = System.getProperty("java.vm.vendor", "").contains("Oracle") || System.getProperty("java.vm.name", "").contains("HotSpot");

Try / catch

try {
  sessionFactory.getConfiguration().addMapper(RecordMapper.class);
} catch (ReflectionException e) {
  if (e.getMessage().contains("isRecord")) {
    // fall back to a class-based DTO instead of a record on this runtime
  }
}

Prevention

When it happens

Trigger: Running on a non-standard JVM or bytecode-rewritten runtime (AOP agents, Android-derived runtimes, some GraalVM/native-image configurations) where MethodHandle invocation of Class.isRecord fails; also possible if the class is redefined concurrently.

Common situations: Record resultTypes under an instrumented/transformed classloader; exotic JVM forks; native-image builds where method handle intrinsics are unavailable.

Related errors


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