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)
Approach for centralizing unknown enum handling
The handling of enums can be improved by centralizing the
fromValuelogic.1. New
EnumUtilsutility (hand-written, non-generated)src/main/java/com/adyen/util/EnumUtils.java2. Template changes (
modelEnum.mustache+modelInnerEnum.mustache)Gated behind a
useEnumUtilsflag — same pattern asuseReflectionEqualsHashCode,handleNullableProperties, anduseNullForUnknownEnumValuealready in the templates.Imports — drop
Loggerwhen flag is on:Enum body — drop the
LOGfield when flag is on:fromValue— delegate to the utility:3. Scope — TAPI-only vs global
Both options are feasible:
useEnumUtils: trueonly in the TAPI config inadyen-sdk-automation. Safe and scoped to this PR, but leaves an inconsistency: TAPI enums useEnumUtils, all other services keep the per-enumLogger.adyen-sdk-automation, re-generate all services. EliminatesLoggerfrom 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)