Consider Enums A BDO

In the past, when I used enums I was always forced to make a decision on how to save it to the database and how to return it to the front-end. I already wrote an earlier blog post about this and how both the ordinal as well as the name have their own drawbacks. Since my recent experimentation with BDOs I have started to try out a new approach, one where I see the enum itself as a BDO.

In the past ordinal, tricky because of order, and name prevents renaming. So I created a specific mapper to convert them. This decouples the values from both database and DTO from the actual enum, meaning it can now update and be modified without any problem. It is the mapper that will guarantee the correct values.

public final class EnumTypeMapper {

    private EnumTypeMapper() {
    }

    public static EnumType fromDto(final String type) {
        Objects.requireNonNull(type);

        return switch (type) {
            case "FOO" -> EnumType.FOO;
            case "BAR" -> EnumType.BAR;
            default -> throw new IllegalArgumentException();
        };
    }

    public static String toDto(final EnumType type) {
        Objects.requireNonNull(type);

        return switch (type) {
            case FOO -> "FOO";
            case BAR -> "BAR";
        };
    }

    public static EnumType fromDao(final int value) {
        return switch (value) {
            case 0 -> EnumType.FOO;
            case 1 -> EnumType.BAR;
            default -> throw new IllegalArgumentException();
        };
    }

    public static int toDao(final EnumType type) {
        Objects.requireNonNull(type);

        return switch (type) {
            case FOO -> 0;
            case BAR -> 1;
        };
    }
}

With the newer Java versions, you don't need to include a default case if you cover all cases. And I even rely on this behaviour to give a compile error when an enum value is added but not to the mapper.

It does add some more boilerplate and overhead, but it centralizes the logic of how to convert/map the data instead of having to implicitly know. As mentioned before, the main advantage is that you can modify the enum values as much as you want without having any impact on the values used for the DAO and DTO.

I do like this approach as it also allows for more robust testing, in the past I would easily rely on the ordinal or name in my test as well, which of course gets updated with the enum. This would result in a breaking change that does not get discovered by my test. To avoid this I did write enum tests to see if the ordinal and name of each value was expected, but this is something you can easily forget or just skip over. Having a dedicated mapper does make all of this logic more explicit, moreover if you consider the enum to be a BDO it should not be responsible for having logic to map it to a value that can be used for a DTO or DAO.