{"record":{"id":"12fe8c60ea0c4647","repo":"SonarSource/sonarqube","slug":"can-not-find-the-mbean-interface-of-class","errorCode":null,"errorMessage":"Can not find the MBean interface of class ","messagePattern":"Can not find the MBean interface of class ","errorType":"exception","errorClass":"IllegalArgumentException","httpStatus":null,"severity":"error","filePath":"server/sonar-process/src/main/java/org/sonar/process/Jmx.java","lineNumber":72,"sourceCode":"   * MBeans have multiple conventions, including:\n   * 1. name of interface is suffixed by \"MBean\"\n   * 2. name of implementation is the name of the interface without \"MBean\"\n   * 3. implementation and interface must be in the same package\n   * To avoid the last convention, we wrap the mbean within a StandardMBean. That\n   * requires to find the related interface.\n   */\n\n  private static Class<Object> guessMBeanInterface(Object instance) {\n    Class<Object> mbeanInterface = null;\n    Class<Object>[] interfaces = (Class<Object>[])instance.getClass().getInterfaces();\n    for (Class<Object> anInterface : interfaces) {\n      if (anInterface.getName().endsWith(\"MBean\")) {\n        mbeanInterface = anInterface;\n        break;\n      }\n    }\n    if (mbeanInterface == null) {\n      throw new IllegalArgumentException(\"Can not find the MBean interface of class \" + instance.getClass().getName());\n    }\n    return mbeanInterface;\n  }\n\n  /**\n   * Unregister a MBean from JMX server. Errors are ignored and logged as warnings.\n   */\n  public static void unregister(String name) {\n    try {\n      ManagementFactory.getPlatformMBeanServer().unregisterMBean(new ObjectName(name));\n    } catch (Exception e) {\n      LoggerFactory.getLogger(Jmx.class).warn(\"Can not unregister MBean [{}]\", name, e);\n    }\n  }\n}\n","sourceCodeStart":54,"sourceCodeEnd":88,"githubUrl":"https://github.com/SonarSource/sonarqube/blob/184c821202192afc1c599fc912d0889b69fffa53/server/sonar-process/src/main/java/org/sonar/process/Jmx.java#L54-L88","documentation":"guessMBeanInterface scans the instance's implemented interfaces for one whose name ends with 'MBean'. If none is found it throws IllegalArgumentException, because StandardMBean requires such an interface.","triggerScenarios":"register(name, instance) where instance's class implements no interface named *MBean (or the matching interface is not public).","commonSituations":"Refactoring renamed the interface dropping the MBean suffix; object implements only non-public interfaces; wrong object passed to register.","solutions":["Make the class implement a public interface whose name ends with 'MBean'","Restore the MBean suffix if a rename removed it","Ensure the interface is public (StandardMBean requirement)","Pass the correct managed object to Jmx.register"],"exampleFix":"// before\npublic interface Watchdog { void check(); }\nclass WatchdogImpl implements Watchdog {}\n// after\npublic interface WatchdogMBean { void check(); }\nclass WatchdogImpl implements WatchdogMBean {}","handlingStrategy":"type-guard","validationCode":"boolean hasMBeanInterface(Object o) {\n  return Arrays.stream(o.getClass().getInterfaces())\n    .anyMatch(i -> i.getName().endsWith(\"MBean\"));\n}","typeGuard":"static boolean isRegisterable(Object instance) {\n  return Arrays.stream(instance.getClass().getInterfaces())\n    .anyMatch(i -> java.lang.reflect.Modifier.isPublic(i.getModifiers()) && i.getName().endsWith(\"MBean\"));\n}","tryCatchPattern":"try { Jmx.register(name, instance); } catch (IllegalArgumentException e) { throw new IllegalStateException(\"Object \" + instance + \" lacks an MBean interface\", e); }","preventionTips":["Name management interfaces with the MBean suffix","Keep management interfaces public","Add a unit test registering each managed bean"],"tags":["jmx","mbean","reflection"],"backgroundTag":"class-not-found","analyzedSha":"184c821202192afc1c599fc912d0889b69fffa53","analyzedAt":"2026-09-09T12:23:51.573Z","contentChangedAt":"2026-09-09T12:23:51.573Z","schemaVersion":2},"datasetVersion":"2026-09-17T15:17:12.973Z"}