{"record":{"id":"1f359106cd1481fc","repo":"mybatis/mybatis-3","slug":"failed-to-invoke-class-isrecord","errorCode":null,"errorMessage":"Failed to invoke 'Class.isRecord()'.","messagePattern":"Failed to invoke 'Class\\.isRecord\\(\\)'\\.","errorType":"exception","errorClass":"ReflectionException","httpStatus":null,"severity":"error","filePath":"src/main/java/org/apache/ibatis/reflection/Reflector.java","lineNumber":491,"sourceCode":"   *\n   * @return True if the object has a readable property by the name\n   */\n  public boolean hasGetter(String propertyName) {\n    return getMethods.containsKey(propertyName);\n  }\n\n  public String findPropertyName(String name) {\n    return caseInsensitivePropertyMap.get(name.toUpperCase(Locale.ENGLISH));\n  }\n\n  /**\n   * Class.isRecord() alternative for Java 15 and older.\n   */\n  private static boolean isRecord(Class<?> clazz) {\n    try {\n      return isRecordMethodHandle != null && (boolean) isRecordMethodHandle.invokeExact(clazz);\n    } catch (Throwable e) {\n      throw new ReflectionException(\"Failed to invoke 'Class.isRecord()'.\", e);\n    }\n  }\n\n  private static MethodHandle getIsRecordMethodHandle() {\n    MethodHandles.Lookup lookup = MethodHandles.lookup();\n    MethodType mt = MethodType.methodType(boolean.class);\n    try {\n      return lookup.findVirtual(Class.class, \"isRecord\", mt);\n    } catch (NoSuchMethodException | IllegalAccessException e) {\n      return null;\n    }\n  }\n}\n","sourceCodeStart":473,"sourceCodeEnd":505,"githubUrl":"https://github.com/mybatis/mybatis-3/blob/008069adb1b089579b5dcba87ee591908b263274/src/main/java/org/apache/ibatis/reflection/Reflector.java#L473-L505","documentation":"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.","triggerScenarios":"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.","commonSituations":"Record resultTypes under an instrumented/transformed classloader; exotic JVM forks; native-image builds where method handle intrinsics are unavailable.","solutions":["Run on a standard JDK 16+ (or any supported stock JDK) and re-test.","Disable class transformers/agents that rewrite java.lang.Class or the application classes involved.","If on GraalVM native-image, ensure a recent version with full MethodHandle support and proper reflection metadata registered."],"exampleFix":null,"handlingStrategy":"fallback","validationCode":"if (Runtime.version().feature() >= 16 && Runtime.getPages... ) { /* placeholder */ }\n// simpler: detect standard JVM before relying on record resultTypes\nboolean recordsSafe = System.getProperty(\"java.vm.vendor\", \"\").contains(\"Oracle\") || System.getProperty(\"java.vm.name\", \"\").contains(\"HotSpot\");","typeGuard":null,"tryCatchPattern":"try {\n  sessionFactory.getConfiguration().addMapper(RecordMapper.class);\n} catch (ReflectionException e) {\n  if (e.getMessage().contains(\"isRecord\")) {\n    // fall back to a class-based DTO instead of a record on this runtime\n  }\n}","preventionTips":["Test record resultTypes on the exact production JVM early in the project.","Keep a class-based DTO variant for environments with restricted MethodHandle support."],"tags":["mybatis","reflection","records","jvm","methodhandle"],"backgroundTag":null,"analyzedSha":"008069adb1b089579b5dcba87ee591908b263274","analyzedAt":"2026-08-14T13:07:10.264Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}