class KeyState {

    final Function<HasMetadata, String> keyFunction;
    final Function<String, String[]> keyFieldFunction;
    final List<String[]> keyFields;

    /**
     * The key function must decompose a given key into the given fields - in field order
     *
     * @param keyFieldFunction to convert a key into fields
     * @param keyFields the fields represented by the key
     */
    public KeyState(Function<HasMetadata, String> keyFunction, Function<String, String[]> keyFieldFunction,
        String[]... keyFields) {
      this.keyFunction = keyFunction;
      this.keyFieldFunction = keyFieldFunction;
      this.keyFields = Arrays.asList(keyFields);
    }

  }

  public static final KeyState NAME_KEY_STATE = new KeyState(Cache::metaNamespaceKeyFunc,
      k -> {
        int index = k.indexOf("/");
        if (index == -1) {
          return new String[] { null, k };
        }
        return new String[] { k.substring(0, index), k.substring(index + 1) };
      }, new String[] { METADATA, "namespace" }, new String[] { METADATA, "name" });

  public static final KeyState UID_KEY_STATE = new KeyState(Cache::metaUidKeyFunc,
      k -> new String[] { k }, new String[] { METADATA, "uid" });

  /**
   * Create a state store with only the fields specified.
   * <p>
   * metadata.resourceVersion - will automatically be saved as will
   * the necessary key fields.
   * <p>
   * If you are using custom indexers, then the fields used by those
   * indexes must be added to the valueFields - otherwise the indexer won't be able to delete the
   * index entries when the item is removed.
   * <p>
   * For example in level event handling systems all you may need beyond the
   * key is the ownerReferences. You would use withValueFields("metadata.ownerReferences")
   * for that.
   * <p>
   * NOTE: If you use this feature, you should only use the informer cache/store for basic
   * existence checks and maintain your own cache of full resource objects.
   * <p>
   * Only simple names are allowed in field paths - '.' is reserved as the separator.
   * <p>
   * Whatever is provided as the {@link KeyState} should match the keyFunction provided to the informer.
   *
   * @param keyState information about the key fields/function
   * @param typeClass the expected type
   * @param valueFields the additional fields to save
   */
  public ReducedStateItemStore(KeyState keyState, Class<V> typeClass, KubernetesSerialization serialization,
      String... valueFields) {
    this.keyState = keyState;
    fields.add(new String[] { METADATA, "resourceVersion" });
    if (valueFields != null) {
      for (int i = 0; i < valueFields.length; i++) {
        fields.add(valueFields[i].split("\\."));
      }
    }
    this.typeClass = typeClass;
    this.serialization = serialization;
  }

  Object[] store(V value) {
    if (value == null) {
      return null;
    }
    Map<String, Object> raw = serialization.convertValue(value, Map.class);
    return fields.stream().map(f -> GenericKubernetesResource.get(raw, (Object[]) f)).toArray();
  }

  V restore(String key, Object[] values) {<FILL_FUNCTION_BODY>

    if (values == null) {
      return null;
    }
    Map<String, Object> raw = new HashMap<>();
    applyFields(values, raw, this.fields);
    String[] keyParts = this.keyState.keyFieldFunction.apply(key);
    applyFields(keyParts, raw, this.keyState.keyFields);

    return serialization.convertValue(raw, typeClass);
  
<no_super_class>