Skip to content

Approach for centralizing unknown enum handling #1910

Description

@gcatanese

Approach for centralizing unknown enum handling

The handling of enums can be improved by centralizing the fromValue logic.

1. New EnumUtils utility (hand-written, non-generated)

src/main/java/com/adyen/util/EnumUtils.java

public final class EnumUtils {
    private static final Logger LOG = Logger.getLogger(EnumUtils.class.getName());

    private EnumUtils() {}

    public static <T extends Enum<T>> T fromValue(
            Class<T> enumClass, String value, Function<T, String> getValue) {
        for (T b : enumClass.getEnumConstants()) {
            if (getValue.apply(b).equals(value)) return b;
        }
        LOG.warning(String.format("%s: unexpected enum value '%s' - Supported values are %s",
            enumClass.getSimpleName(), value, Arrays.toString(enumClass.getEnumConstants())));
        return null;
    }
}

2. Template changes (modelEnum.mustache + modelInnerEnum.mustache)

Gated behind a useEnumUtils flag — same pattern as useReflectionEqualsHashCode, handleNullableProperties, and useNullForUnknownEnumValue already in the templates.

Imports — drop Logger when flag is on:

{{^useEnumUtils}}
import java.util.logging.Logger;
{{/useEnumUtils}}

Enum body — drop the LOG field when flag is on:

{{^useEnumUtils}}
  private static final Logger LOG = Logger.getLogger({{{datatypeWithEnum}}}.class.getName());
{{/useEnumUtils}}

fromValue — delegate to the utility:

  public static {{{datatypeWithEnum}}} fromValue({{{dataType}}} value) {
{{#useEnumUtils}}
    return com.adyen.util.EnumUtils.fromValue(
        {{{datatypeWithEnum}}}.class, value, {{{datatypeWithEnum}}}::getValue);
{{/useEnumUtils}}
{{^useEnumUtils}}
    for ({{{datatypeWithEnum}}} b : {{{datatypeWithEnum}}}.values()) {
      if (b.value.equals(value)) return b;
    }
    LOG.warning(String.format(
        "{{{datatypeWithEnum}}}: unexpected enum value '%s' - Supported values are %s",
        value, Arrays.toString({{{datatypeWithEnum}}}.values())));
    return null;
{{/useEnumUtils}}
  }

3. Scope — TAPI-only vs global

Both options are feasible:

  • TAPI-only: Set useEnumUtils: true only in the TAPI config in adyen-sdk-automation. Safe and scoped to this PR, but leaves an inconsistency: TAPI enums use EnumUtils, all other services keep the per-enum Logger.
  • Global (recommended): Set the flag across all service configs in adyen-sdk-automation, re-generate all services. Eliminates Logger from every generated enum consistently — which seems to be the intent of the original suggestion.

TAPI-only is a one-liner per config file in the automation repo and easy to do now; globally applying it later is equally straightforward since it's just a flag flip.


Also: the String.format() suggestion applies to the fallback (non-useEnumUtils) path in the template as well — worth fixing there too regardless of which direction we go.

Originally posted by @thomasc-adyen in #1906 (comment)

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions