Java Enum Design & Generic Utility
Java Enum Design & Generic Utility
1. Problem Background
In many business scenarios, enums need to convert from a String value:
1 | StudentStatus.from("enrolled"); |
Without abstraction, every enum repeats the same logic:
1 | for (StudentStatus s : StudentStatus.values()) { |
This leads to code duplication and poor maintainability. We need to keep code dry
2. Goal
Eliminate repeated
from()logicKeep type safety
Maintain clean and readable API
Make the solution reusable across all enums
3. Final Design (Best Practice)
3.1 Base Interface
1 | public interface BaseEnum { |
Purpose:
- Defines a contract
- Ensures all enums expose
getValue()
3.2 Generic Utility Class
1 | public class EnumUtil { |
3.3 Enum Implementation
1 |
|
4. Key Concepts Explained
4.1 Why Use an Interface?
Without BaseEnum:
1 | <T extends Enum<T>> |
The compiler only knows it’s an enum
It does NOT know getValue() exists
With BaseEnum:
1 | <T extends Enum<T> & BaseEnum> |
Now the compiler guarantees:
getValue()exists
4.2 Lombok vs Interface
| Feature | Lombok | Interface |
|---|---|---|
| Generate getter | ✅ | ❌ |
| Enforce method existence | ❌ | ✅ |
Lombok helps reduce code
Interface ensures type safety
4.3 Understanding Generics
A named type parameter
Can be used throughout the method
?
An anonymous wildcard
Cannot be used for operations
4.4 Difference: T vs ?
| Feature | T |
? |
|---|---|---|
| Has a name | ✅ | ❌ |
| Can be used as return type | ✅ | ❌ |
| Can be modified | ✅ | ❌ |
| Read-only usage | ✅ | ✅ |
4.5 Class<T> vs Class<?>
| Type | Meaning |
|---|---|
Class<T> |
Known specific type |
Class<?> |
Unknown type |
Example:
1 | Class<StudentStatus> clazz = StudentStatus.class; // specific |
5. Why Not Skip the Interface?
Option 1: Use Lombok only
Problem:
- Compiler cannot confirm
getValue() - Generic method fails
Option 2: Use name()
1 | constant.name().equals(value) |
Problems:
- Not flexible
- Tightly coupled to enum names
- Not suitable for real business cases
Option 3: Use Reflection
1 | constant.getClass().getMethod("getValue") |
Problems:
- Slow
- Unsafe
- Hard to maintain
6. Why Keep from() Inside Enum?
Better readability:
1 | StudentStatus.from("enrolled"); |
vs
1 | EnumUtil.fromValue(StudentStatus.class, "enrolled"); |
Enum version is more expressive and domain-oriented
7. Design Philosophy
Key Idea:
Interfaces are not for writing code — they are for enforcing contracts.
Good Design =
- Simple usage
- Strong constraints internally
- Reusable components
8. Final Takeaways
Use interface + generic utility + enum wrapper
Lombok is for convenience, not for type safety
Generics (
T) enable reusable and safe designAvoid shortcuts that sacrifice maintainability









