The main use: make sure that you always handle all available constants of an enum. An annotation processor will
make sure that you get a compile-time error otherwise: see Full Enum Mapper.
You can also use a Partial Mapper and it supports Reverse Mapping.
Since version 1.4 Incremental Annotation Processing
is supported for Gradle builds.
The project is available in Maven Central and JCenter-Bintray repositories.
final VERSION_ENUM_MAPPER = '1.0.4' // check for newer versions here: https://goo.gl/LSP1fv
implementation "com.tmtron.enums:enum-mapper-lib:${VERSION_ENUM_MAPPER}"
annotationProcessor "com.tmtron.enums:enum-mapper-processor:${VERSION_ENUM_MAPPER}"
Contains java code and annotations.
This is always needed at compile-time.
Contains the annotation-processor.
This is needed by the annotation-processing build-step (apt
) and it is only required for the Full Enum Mapper.
Just annotate your enum with the @EnumMapper
annotation:
@EnumMapper
public enum Seasons {
SPRING, SUMMER, FALL, WINTER
}
When you build your project, the annotation processor will generate a java class Seasons_MapperFull
,
which can be used to map all enum constants to arbitrary values.
Here is an example use where we map each enum constant to a string.
EnumMapperFull<Seasons, String> germanSeasons = Seasons_MapperFull
.setSPRING("Fruehling")
.setSUMMER("Sommer")
.setFALL("Herbst")
.setWINTER("Winter");
String germanSummer = germanSeasons.getValue(Seasons.SUMMER); // returns "Sommer"
The great thing about this is that you will get a compile time error, when you forget to map any enum-constant - or when you change the enumeration (e.g. add or remove an enum-constant).
Detailed usage examples are also available on the github enum-mapper-example project
You can also generate full-mappers for Enums that you don't control. Just add the @EnumMappers
(note the plural form!) annotation to any class and reference the enum classes that you want to map.
For example let's assume, that you use a 3rd party library which defines these enums:
public enum ColorEnum {
RED, BLUE, GREEN
}
public enum BoolEnum {
ON, OFF
}
Since you cannot change the source code of the 3rd party library, you cannot add the @EnumMapper
annotation
to the enum classes.
Instead you can use the the @EnumMappers
(note the plural form!) annotation on any of your own classes, like this:
@EnumMappers({ColorEnum.class, BoolEnum.class})
public class AppUtil {
// your code here
}
Then the annotation processor will create a full enum-mapper for ColorEnum
and for BoolEnum
.
Hint: when you want to map a single enum, you don't need the curly braces (for the array-syntax)
@EnumMappers(ColorEnum.class)
public class AppUtil {
// your code here
}
The project also includes a partial enum-mapper class which you may want to use instead of a switch statement.
Note. The partial enum mapper does not need the annotation processor.
An example of a partial mapper for your Seasons
enum:
EnumMapperPartial<Seasons, String> extremeSeasons =
EnumMapperPartial.of(SUMMER, "Sommer"
, WINTER, "Winter");
Now you can call the getValueOrNull
or getValueOrDefault
methods like this:
extremeSeasons.getValueOrNull(SUMMER); // returns "Sommer"
extremeSeasons.getValueOrNull(WINTER); // returns "Winter"
extremeSeasons.getValueOrNull(SPRING)); // returns null
extremeSeasons.getValueOrDefault(SPRING, "not extreme"); // returns "not extreme"
extremeSeasons.getValueOrRaise(SPRING); // throws an IllegalArgumentException
extremeSeasons.isEnumMapped(SUMMER); // returns true
extremeSeasons.isEnumMapped(SPRING); // returns false
The full and the partial mappers also support reverse lookup.
For example, we can use the extremeSeasons
mapper to get the enum-constant for a string, like this:
extremeSeasons.getEnumOrNull("Sommer"); // returns the enum-constant SUMMER
extremeSeasons.getEnumOrDefault("Fruehling", FALL)); // returns the enum-constant FALL
extremeSeasons.getEnumOrRaise("Fruehling"); // throws an IllegalArgumentException
extremeSeasons.isValueMapped("Sommer"); // returns true
extremeSeasons.isValueMapped("Fruehling"); // returns false
When you do a reverse mapping the mapped values should of course be unique.
This section mentions some alternative approaches that you can use instead of this annotation processor.
See also: Stackoverflow: How to ensure completeness in an enum switch at compile time?
As mentioned in this Stackoverflow answer you can have abstract methods on your enum definition.
public enum AlternativeBool {
ON {
@Override
public String getGermanName() {
return "ein";
}
}
, OFF {
@Override
public String getGermanName() {
return "aus";
}
};
public abstract String getGermanName();
}
Advantages
- this approach does not need an annotation processor
- you also get a compile-time error should you forget to implement a method for a new enum
Disadvantages
- it is quite verbose
- you can only use this for enums that you control
Some IDEs allow you to activate a check that will warn you when you forget an enum constant in a switch statement:
Advantages
- this approach does not need an annotation processor
- direct and immediate feedback
Disadvantages
- you could forget to active the switch
- someone members of your team may use other IDEs which don't support this feature
For example FindBugs has a check Switch statement found where default case is missing SF_SWITCH_NO_DEFAULT
Advantages
- other tools may offer way more functionality
Disadvantages
- those are other tools that you must learn to use and maintain
This plugin is under the Apache 2.0 license. Copyright 2018, Martin Trummer