class Adapters {

  private final Set<ClassLoader> classLoaders = Collections.newSetFromMap(new ConcurrentHashMap<>());
  private final Map<Class<?>, ExtensionAdapter<?>> extensionAdapters = new ConcurrentHashMap<>();
  private final Handlers handlers;

  public Adapters(Handlers handlers) {
    this.handlers = handlers;
    discoverServices(Adapters.class.getClassLoader());
    discoverServices(Thread.currentThread().getContextClassLoader());
  }

  public <T extends Client, C extends ClientAdapter<C>> void registerClient(Class<T> type, ClientAdapter<C> target) {<FILL_FUNCTION_BODY>}

  public <C extends Client> void register(ExtensionAdapter<C> adapter) {
    if (extensionAdapters.putIfAbsent(adapter.getExtensionType(), adapter) == null) {
      adapter.registerResources(this::registerResource);
      adapter.registerClients(this::registerClient);
      if (adapter instanceof InternalExtensionAdapter) {
        ((InternalExtensionAdapter) adapter).registerHandlers(handlers);
      }
    }
  }

  public <C extends Client> void unregister(ExtensionAdapter<C> adapter) {
    extensionAdapters.remove(adapter.getExtensionType());
    // TODO: remove handlers and other state
  }

  public <C extends Client> ExtensionAdapter<C> get(Class<C> type) {
    discoverServices(type.getClassLoader());
    return (ExtensionAdapter<C>) extensionAdapters.get(type);
  }

  private void discoverServices(ClassLoader classLoader) {
    if (classLoader != null && classLoaders.add(classLoader)) {
      for (ExtensionAdapter<?> adapter : ServiceLoader.load(ExtensionAdapter.class, classLoader)) {
        register(adapter);
      }
    }
  }

  public <T extends HasMetadata, R extends ExtensibleResourceAdapter<T>> void registerResource(
      Class<T> type, R target) {
    ResourceDefinitionContext definitionContest = ResourceDefinitionContext.fromResourceType(type);
    Class<? extends KubernetesResourceList> listType = KubernetesResourceUtil.inferListType(type);
    handlers.register(type,
        c -> new ResourcedHasMetadataOperation<>(HasMetadataOperationsImpl.defaultContext(c),
            definitionContest, type,
            listType, target));
  }

}

    if (!type.isAssignableFrom(target.getClass())) {
      throw new IllegalArgumentException("The adapter should implement the type");
    }
    if (target.getClient() != null) {
      throw new IllegalArgumentException("The client adapter should already be initialized");
    }
    ExtensionAdapter<C> adapter = new ExtensionAdapter<C>() {

      @Override
      public Class getExtensionType() {
        return type;
      }

      @Override
      public C adapt(Client client) {
        C result = target.newInstance();
        result.init(client);
        return result;
      }

    };
    extensionAdapters.put(type, adapter);
    // some of the old extension adapters were inconsistent - and
    // specified the client class, rather than the dsl/interface
    // alternatively - we could just leave the type blank and scan the class hierarchy
    extensionAdapters.put(target.getClass(), adapter);
  
<no_super_class>