@VisibleForTesting
  public static <ConfigT> ConfigT payloadToConfig(
      ExternalConfigurationPayload payload, Class<ConfigT> configurationClass) {
    try {
      return payloadToConfigSchema(payload, configurationClass);
    } catch (NoSuchSchemaException schemaException) {
      LOG.warn(
          "Configuration class '{}' has no schema registered. Attempting to construct with setter"
              + " approach.",
          configurationClass.getName());
      try {
        return payloadToConfigSetters(payload, configurationClass);
      } catch (ReflectiveOperationException e) {
        throw new IllegalArgumentException(
            String.format(
                "Failed to construct instance of configuration class '%s'",
                configurationClass.getName()),
            e);
      }
    }
  }
@Test
  public void testCompoundCodersForExternalConfiguration_setters() throws Exception {
    ExternalTransforms.ExternalConfigurationPayload externalConfig =
        encodeRowIntoExternalConfigurationPayload(
            Row.withSchema(
                    Schema.of(
                        Field.nullable("config_key1", FieldType.INT64),
                        Field.nullable("config_key2", FieldType.iterable(FieldType.BYTES)),
                        Field.of("config_key3", FieldType.map(FieldType.STRING, FieldType.INT64)),
                        Field.of(
                            "config_key4",
                            FieldType.map(FieldType.STRING, FieldType.array(FieldType.INT64)))))
                .withFieldValue("config_key1", 1L)
                .withFieldValue("config_key2", BYTE_LIST)
                .withFieldValue("config_key3", BYTE_KV_LIST)
                .withFieldValue("config_key4", BYTE_KV_LIST_WITH_LIST_VALUE)
                .build());

    TestConfigSetters config =
        ExpansionService.payloadToConfig(externalConfig, TestConfigSetters.class);

    assertThat(config.configKey1, Matchers.is(1L));
    assertThat(config.configKey2, contains(BYTE_LIST.toArray()));
    assertThat(config.configKey3, is(notNullValue()));
    // no-op for checker framework
    if (config.configKey3 != null) {
      assertThat(
          config.configKey3.entrySet(),
          containsInAnyOrder(
              BYTE_KV_LIST.entrySet().stream()
                  .map(
                      (entry) ->
                          allOf(
                              hasProperty("key", equalTo(entry.getKey())),
                              hasProperty("value", equalTo(entry.getValue()))))
                  .collect(Collectors.toList())));
    }
    assertThat(config.configKey4, is(notNullValue()));
    // no-op for checker framework
    if (config.configKey4 != null) {
      assertThat(
          config.configKey4.entrySet(),
          containsInAnyOrder(
              BYTE_KV_LIST_WITH_LIST_VALUE.entrySet().stream()
                  .map(
                      (entry) ->
                          allOf(
                              hasProperty("key", equalTo(entry.getKey())),
                              hasProperty("value", equalTo(entry.getValue()))))
                  .collect(Collectors.toList())));
    }
  }