How to Build a Flexible Enum Dictionary API in Java with Lambda Magic
This article explains how to design a reusable Java enum‑based dictionary API, extract common key/label properties, extend it with custom fields, and use lambda expressions together with reflection to generate clean JSON lists without hard‑coded magic strings.
Background
In typical backend development we use enum dictionaries to represent types such as gender, order status, payment method, etc.
1.1 Common Enum
A standard Java enum is defined with @Getter and @AllArgsConstructor and contains key and label fields.
@Getter
@AllArgsConstructor
public enum NotifyChannel {
WORK_WECHAT(1, "企业微信"),
FEI_SHU(2, "飞书");
private final int key;
private final String label;
}For the frontend we usually expose the data as JSON:
[
{"key":1, "label":"企业微信"},
{"key":2, "label":"飞书"}
]1.2 Extended Enum
Sometimes extra attributes are needed, e.g. a color field.
@Getter
@AllArgsConstructor
public enum Gender {
MALE(1, "男", "#409EFF"),
FEMALE(2, "女", "#67C23A");
private final int key;
private final String label;
private final String color;
}We need an API that can return these dictionary values.
Implementation
2.1 Extract Common Properties
Define a standard interface that all enums implement:
public interface IDictionary {
int getKey();
String getLabel();
}Each enum implements IDictionary and provides the required methods.
2.2 Traverse Enums
Use clazz.getEnumConstants() to iterate over all enum items.
Arrays.stream(clazz.getEnumConstants()).forEach(enumItem -> {
// process each item
});2.3 Dictionary Utility
Create a DictionaryUtil class to build a list of maps from the enum values.
public class DictionaryUtil {
public static <D extends IDictionary> List<Map<String, Object>> getDictionaryList(@NotNull Class<D> clazz) {
List<Map<String, Object>> mapList = new ArrayList<>();
Arrays.stream(clazz.getEnumConstants()).forEach(enumItem -> {
Map<String, Object> item = new HashMap<>(2);
item.put("key", enumItem.getKey());
item.put("label", enumItem.getLabel());
mapList.add(item);
});
return mapList;
}
}This works for the basic key / label pair but not for additional fields.
If we also need the color attribute we would have to write another method, which is inconvenient.
2.4 Overload with Custom Properties
Provide an overloaded method that accepts property names:
public static <D extends IDictionary> List<Map<String, Object>> getDictionaryLists(@NotNull Class<D> clazz, String... props) {
List<Map<String, Object>> mapList = new ArrayList<>();
Arrays.stream(clazz.getEnumConstants()).forEach(enumItem -> {
Map<String, Object> item = new HashMap<>(2);
for (String prop : props) {
try {
Method method = clazz.getMethod("get" + StringUtils.capitalize(prop));
Object value = method.invoke(enumItem);
item.put(prop, value);
} catch (Exception e) {
log.error(e.getMessage(), e);
}
}
mapList.add(item);
});
return mapList;
}Calling it with property names still relies on magic strings and may reference non‑existent fields.
Passing arbitrary strings as property names is not elegant and can introduce magic values.
We prefer a type‑safe approach using method references.
Lambda Optimization
Introduce a functional interface that extends Function and Serializable:
@FunctionalInterface
public interface IFunction<T, R> extends Function<T, R>, Serializable {}Use reflection to extract the method name from a lambda expression:
public static String getLambdaFunctionName(@NotNull IFunction<?, ?> lambda) {
try {
Method writeReplace = lambda.getClass().getDeclaredMethod("writeReplace");
writeReplace.setAccessible(true);
SerializedLambda sl = (SerializedLambda) writeReplace.invoke(lambda);
return sl.getImplMethodName().replace("get", "");
} catch (Exception e) {
throw new ServiceException(e);
}
}Now we can pass method references and automatically obtain the property names:
DictionaryUtil.getDictionaryList(ServiceError.class, ServiceError::getKey, ServiceError::getLabel);The utility iterates over the provided lambdas, derives the property name, and puts the returned value into the map.
Arrays.stream(clazz.getEnumConstants()).forEach(enumItem -> {
Map<String, Object> item = new HashMap<>(lambdas.length);
Arrays.stream(lambdas).forEach(lambda -> {
try {
String prop = StringUtils.uncapitalize(ReflectUtil.getLambdaFunctionName(lambda));
item.put(prop, lambda.apply(enumItem));
} catch (Exception e) {
log.error(e.getMessage(), e);
}
});
mapList.add(item);
});Finally, the API can be used elegantly:
DictionaryUtil.getDictionaryList(ServiceError.class);
DictionaryUtil.getDictionaryList(ServiceError.class, ServiceError::getKey, ServiceError::getLabel);
DictionaryUtil.getDictionaryList(UserGender.class, UserGender::getKey, UserGender::getLabel, UserGender::getColor);Summary
The article demonstrates a clean, type‑safe way to expose enum dictionaries as JSON lists in Java, evolving from a simple key/label implementation to a flexible lambda‑based solution that avoids magic strings and supports arbitrary enum fields.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Rare Earth Juejin Tech Community
Juejin, a tech community that helps developers grow.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
