/**
   * Instantiate, configure and return a new component described by the supplied configuration. This
   * method does not manage the returned instance.
   *
   * @param config the configuration describing the component
   * @return the new component, or null if the component could not be successfully configured
   * @throws IllegalArgumentException if the component could not be configured properly
   */
  @SuppressWarnings("unchecked")
  protected ComponentType newInstance(ConfigType config) {
    String[] classpath = config.getComponentClasspathArray();
    final ClassLoader classLoader = this.getClassLoaderFactory().getClassLoader(classpath);
    assert classLoader != null;
    ComponentType newInstance = null;
    try {
      // Don't use ClassLoader.loadClass(String), as it doesn't properly initialize the class
      // (specifically static initializers may not be called)
      Class<?> componentClass = Class.forName(config.getComponentClassname(), true, classLoader);
      newInstance = doCreateInstance(componentClass);
      if (newInstance instanceof Component) {
        ((Component<ConfigType>) newInstance).setConfiguration(config);
      }

      if (config.getProperties() != null) {
        for (Map.Entry<String, Object> entry : config.getProperties().entrySet()) {
          // Set the JavaBean-style property on the RepositorySource instance ...
          Reflection reflection = new Reflection(newInstance.getClass());
          reflection.invokeSetterMethodOnTarget(entry.getKey(), newInstance, entry.getValue());
        }
      }
      configure(newInstance, config);
    } catch (Throwable e) {
      throw new SystemFailureException(e);
    }
    if (newInstance instanceof Component
        && ((Component<ConfigType>) newInstance).getConfiguration() == null) {
      throw new SystemFailureException(CommonI18n.componentNotConfigured.text(config.getName()));
    }
    return newInstance;
  }