Converting/Parsing an Enumeration to a String More Generically
Analysis
Most of the work involved in scaling the below out would just be in maintaining the enumWrappers
map. If you have varied namespacing, you may need to adjust the getEnumeration
strategy somewhat. IMO it's a little strong to throw an exception if you can't find what you want, so I just return null
.
Strategy
It might help to use a wrapper class (top-level or otherwise) something like:
public class EnumWrapper
{
final Map<String, Object> values;
public EnumWrapper(List<Object> enumValues)
{
values = new Map<String, Object>();
for (Object enumValue : enumValues)
{
values.put(String.valueOf(enumValue).toUpperCase(), enumValue);
}
}
public Object getValue(String enumeration)
{
return String.isBlank(enumeration) ? null :
values.get(enumeration.toUpperCase());
}
}
Then you could use a Map<Type, EnumWrapper>
like:
public with sharing class EnumPoc
{
public Enum Season { SPRING, SUMMER, FALL, WINTER }
public Enum Beverage { TEA, BEER, COFFEE }
public Enum Etc { LOREM, IPSUM }
static Map<Type, EnumWrapper> enumWrappers
{
get
{
if (enumWrappers == null)
{
enumWrappers = new Map<Type, EnumWrapper>
{
Type.forName('EnumPoc.Season') => new EnumWrapper(Season.values()),
Type.forName('EnumPoc.Beverage') => new EnumWrapper(Beverage.values()),
Type.forName('EnumPoc.Etc') => new EnumWrapper(Etc.values())
};
}
return enumWrappers;
}
private set;
}
public static Object getEnumeration(String enumType, String enumValue)
{
EnumWrapper wrapper = enumWrappers.get(Type.forName('EnumPoc', enumType));
return (wrapper == null) ? null : wrapper.getValue(enumValue);
}
}
Debug testing:
system.debug(EnumPoc.getEnumeration('EnumPoc.season', 'winter')); // WINTER
system.debug(EnumPoc.getEnumeration('EnumPoc.beverage', 'beer')); // BEER
system.debug(EnumPoc.getEnumeration('EnumPoc.etc', 'bogus')); // null
With quite a bit of magic, I've come up with a generic method that should work for any enum type (haven't tested with custom namespaces):
public static Object parseEnum(string enumString, Type enumType) {
Type cType = Type.forName(String.format('List<{0}>', new List<String>{ enumType.getName() }));
return ((List<Object>) JSON.deserialize(String.format('["{0}"]', new List<String>{ enumString }), cType))[0];
}
Calling it is a bit awkward, but still better than other solutions IMO:
TriggerOperation operationType = (TriggerOperation)
parseEnum('before_delete', TriggerOperation.class);
System.debug(operationType); // -> BEFORE_DELETE
Explanation
In what seems like a bug, enums are not "round-trip" serializable. IOW, the following code will fail with an error: System.JSONException: Malformed JSON: Expected '{' at the beginning of object
TriggerOperation op = (TriggerOperation) JSON.Deserialize(
JSON.serialize(TriggerOperation.BEFORE_INSERT),
TriggerOperation.class
);
However, when enums are a class
property or in a List
they deserialize without issue. The Solution takes advantage of the latter.