docs: @VisibleForTesting
    Collection<PluginClassLoaderDef> defineClassloaders(Map<String, PluginInfo> infoByKeys) {
      Map<String, PluginClassLoaderDef> classloadersByBasePlugin = new HashMap<>();
  
      for (PluginInfo info : infoByKeys.values()) {
        String baseKey = basePluginKey(info, infoByKeys);
        PluginClassLoaderDef def = classloadersByBasePlugin.get(baseKey);
        if (def == null) {
          def = new PluginClassLoaderDef(baseKey);
          classloadersByBasePlugin.put(baseKey, def);
        }
        ExplodedPlugin explodedPlugin = jarExploder.explode(info);
        def.addFiles(asList(explodedPlugin.getMain()));
        def.addFiles(explodedPlugin.getLibs());
        def.addMainClass(info.getKey(), info.getMainClass());
  
        for (String defaultSharedResource : DEFAULT_SHARED_RESOURCES) {
          def.getExportMask().addInclusion(String.format("%s/%s/api/", defaultSharedResource, info.getKey()));
        }
  
        // The plugins that extend other plugins can only add some files to classloader.
        // They can't change metadata like ordering strategy or compatibility mode.
        if (Strings.isNullOrEmpty(info.getBasePlugin())) {
          def.setSelfFirstStrategy(info.isUseChildFirstClassLoader());
          Version minSqVersion = info.getMinimalSqVersion();
          boolean compatibilityMode = minSqVersion != null && minSqVersion.compareToIgnoreQualifier(COMPATIBILITY_MODE_MAX_VERSION) < 0;
          if (compatibilityMode) {
            Loggers.get(getClass()).warn("API compatibility mode is no longer supported. In case of error, plugin {} [{}] should package its dependencies.",
              info.getName(), info.getKey());
          }
        }
      }
      return classloadersByBasePlugin.values();
  
    }