1818import com .google .auto .common .MoreElements ;
1919import com .google .auto .common .MoreTypes ;
2020import com .google .common .base .Optional ;
21+ import com .google .common .collect .ArrayListMultimap ;
2122import com .tmtron .enums .EnumMappers ;
2223
24+ import java .util .Collection ;
2325import java .util .List ;
26+ import java .util .Map ;
27+ import java .util .Set ;
2428
2529import javax .annotation .processing .ProcessingEnvironment ;
2630import javax .lang .model .element .AnnotationMirror ;
@@ -37,47 +41,102 @@ class MapAllEnumsHandler {
3741
3842 // the EnumMappers class must have a member named value (array of Enum classes)
3943 private static final String ENUMS_ID = "value" ;
40- private final AnnotationMirror annotationMirrorMapAllEnums ;
4144 private final ProcessingEnvironment processingEnvironment ;
42- private final Element annotatedElement ;
45+ private final Set <Element > annotatedElements ;
46+ ;
4347
4448 /**
4549 * Will process an element (e.g. a class) which must have the {@link EnumMappers} annotation.
4650 * Note: the {@link EnumMappers} annotation may contain multiple Enum classes in the enums class array.
4751 *
4852 * @param processingEnvironment the processing environment
49- * @param annotatedElement the element (e.g. class) which has the {@link EnumMappers} annotation
53+ * @param annotatedElements the element/s (e.g. class) which has/have the {@link EnumMappers} annotation
5054 */
51- MapAllEnumsHandler (ProcessingEnvironment processingEnvironment , Element annotatedElement ) {
55+ MapAllEnumsHandler (ProcessingEnvironment processingEnvironment , Set < Element > annotatedElements ) {
5256 this .processingEnvironment = processingEnvironment ;
53- this .annotatedElement = annotatedElement ;
57+ this .annotatedElements = annotatedElements ;
58+ }
59+
60+ /* Returns a map where the keys are all the unique enumerations and the values are the annotated classes
61+ * since V1.0.2 we can use the same enum in multiple @EnumMapper annotations
62+ * see issue #3 "duplicate enums in @EnumMappers should be ignored"
63+ * https://github.com/tmtron/enum-mapper/issues/3
64+ */
65+ private Map <AnnotationValueWrapper , Collection <Element >> getEnumAnnotationsMap () {
66+ ArrayListMultimap <AnnotationValueWrapper , Element > enumAnnotations = ArrayListMultimap .create ();
67+ for (Element annotatedElement : annotatedElements ) {
68+ Optional <AnnotationMirror > optMirror = MoreElements .getAnnotationMirror (annotatedElement , EnumMappers
69+ .class );
70+ if (!optMirror .isPresent ()) {
71+ throw new RuntimeException (EnumMappers .class .getSimpleName () + " annotation not found!" );
72+ }
73+ final AnnotationMirror annotationMirrorMapAllEnums = optMirror .get ();
5474
55- Optional <AnnotationMirror > optMirror = MoreElements .getAnnotationMirror (annotatedElement , EnumMappers .class );
56- if (!optMirror .isPresent ()) {
57- throw new RuntimeException (EnumMappers .class .getSimpleName () + " annotation not found!" );
75+ // get the "value" annotationValue (which is of type: array of classes)
76+ AnnotationValue annotationValue = AnnotationProcessingUtil .getRequiredAnnotationValue
77+ (annotationMirrorMapAllEnums , ENUMS_ID );
78+
79+ // the annotationValue is an array of classes
80+ // we convert it to a list where each item is the class
81+ // e.g. "value" -> {com.test.Dummy.ColorEnum.class, com.test.Dummy.BoolEnum.class}
82+ // --> the enumsList will contain 2 items (ColorEnum and BoolEnum)
83+ List <? extends AnnotationValue > enumsList = AnnotationProcessingUtil .asList (annotationValue .getValue (),
84+ AnnotationValue .class , ENUMS_ID );
85+
86+ // loop over each (Enum-)class in the "value" array
87+ /*
88+ * NOTE: AnnotationValue
89+ */
90+ for (AnnotationValue enumsClassAnnotationValue : enumsList ) {
91+ //noinspection ResultOfMethodCallIgnored
92+ enumAnnotations .put (new AnnotationValueWrapper (enumsClassAnnotationValue ), annotatedElement );
93+ }
5894 }
59- this . annotationMirrorMapAllEnums = optMirror . get ();
95+ return enumAnnotations . asMap ();
6096 }
6197
6298 void work () {
63- // get the "value" annotationValue (which is of type: array of classes)
64- AnnotationValue annotationValue = AnnotationProcessingUtil .getRequiredAnnotationValue
65- (annotationMirrorMapAllEnums , ENUMS_ID );
66-
67- // the annotationValue is an array of classes
68- // we convert it to a list where each item is the class
69- // e.g. "value" -> {com.test.Dummy.ColorEnum.class, com.test.Dummy.BoolEnum.class}
70- // --> the enumsList will contain 2 items (ColorEnum and BoolEnum)
71- List <? extends AnnotationValue > enumsList = AnnotationProcessingUtil .asList (annotationValue .getValue (),
72- AnnotationValue .class , ENUMS_ID );
73-
74- // loop over each (Enum-)class in the "value" array
75- for (AnnotationValue enumsClassAnnotationValue : enumsList ) {
99+ Map <AnnotationValueWrapper , Collection <Element >> enumAnnotationMap = getEnumAnnotationsMap ();
100+
101+ for (AnnotationValueWrapper enumsClassAnnotationValueWrapper : enumAnnotationMap .keySet ()) {
102+ AnnotationValue enumsClassAnnotationValue = enumsClassAnnotationValueWrapper .annotationValue ;
76103 TypeMirror enumsClassTypeMirror = (TypeMirror ) enumsClassAnnotationValue .getValue ();
77104 TypeElement enumsClassTypeElement = MoreTypes .asTypeElement (enumsClassTypeMirror );
105+
106+ Collection <Element > originElements = enumAnnotationMap .get (enumsClassAnnotationValueWrapper );
107+
78108 // now process each (Enum-)class
79109 // e.g. enumsClassTypeElement.getQualifiedName() "com.test.Dummy.BoolEnum.class"
80- new MapEnumElement (processingEnvironment , annotatedElement , enumsClassTypeElement ).work ();
110+ new MapEnumElement (processingEnvironment , originElements , enumsClassTypeElement ).work ();
111+ }
112+ }
113+
114+ /**
115+ * Simple wrapper around an {@link AnnotationValue} that uses the toString() value for equals and hashCode.
116+ */
117+ private static class AnnotationValueWrapper {
118+
119+ final AnnotationValue annotationValue ;
120+ final String stringRep ;
121+
122+ private AnnotationValueWrapper (AnnotationValue annotationValue ) {
123+ this .annotationValue = annotationValue ;
124+ stringRep = annotationValue .toString ();
125+ }
126+
127+ @ Override
128+ public boolean equals (Object o ) {
129+ if (this == o ) return true ;
130+ if (o == null || getClass () != o .getClass ()) return false ;
131+
132+ AnnotationValueWrapper that = (AnnotationValueWrapper ) o ;
133+
134+ return stringRep .equals (that .stringRep );
135+ }
136+
137+ @ Override
138+ public int hashCode () {
139+ return stringRep .hashCode ();
81140 }
82141 }
83142
0 commit comments