Skip to content

Approach for centralizing unknown enum handling #1910

@gcatanese

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)

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