3
3
import dev .openfeature .sdk .OpenFeatureAPI ;
4
4
import dev .openfeature .sdk .providers .memory .Flag ;
5
5
import java .lang .reflect .Method ;
6
+ import java .util .AbstractMap ;
6
7
import java .util .Arrays ;
7
8
import java .util .HashMap ;
9
+ import java .util .HashSet ;
10
+ import java .util .List ;
8
11
import java .util .Map ;
12
+ import java .util .Set ;
13
+ import java .util .stream .Collectors ;
14
+ import java .util .stream .Stream ;
9
15
import org .apache .commons .lang3 .BooleanUtils ;
10
16
import org .junit .jupiter .api .extension .AfterEachCallback ;
11
17
import org .junit .jupiter .api .extension .BeforeEachCallback ;
@@ -23,37 +29,127 @@ public class OpenFeatureExtension implements BeforeEachCallback, AfterEachCallba
23
29
24
30
private static Map <String , Map <String , Flag <?>>> handleExtendedConfiguration (
25
31
ExtensionContext extensionContext , Map <String , Map <String , Flag <?>>> configuration ) {
26
- PioneerAnnotationUtils .findAllEnclosingRepeatableAnnotations (extensionContext , OpenFeature .class )
27
- .forEachOrdered (annotation -> {
28
- Map <String , Flag <?>> domainFlags = configuration .getOrDefault (annotation .domain (), new HashMap <>());
29
-
30
- Arrays .stream (annotation .value ())
31
- .filter (flag -> !domainFlags .containsKey (flag .name ()))
32
- .forEach (flag -> {
33
- Flag .FlagBuilder <?> builder = generateFlagBuilder (flag );
34
- domainFlags .put (flag .name (), builder .build ());
35
- });
36
- configuration .put (annotation .domain (), domainFlags );
37
- });
32
+ List <OpenFeature > openFeatureAnnotationList = PioneerAnnotationUtils .findAllEnclosingRepeatableAnnotations (
33
+ extensionContext , OpenFeature .class )
34
+ .collect (Collectors .toList ());
35
+ Map <String , Set <String >> nonTypedFlagNamesByDomain = getFlagNamesByDomain (openFeatureAnnotationList );
36
+ openFeatureAnnotationList .forEach (annotation -> {
37
+ Map <String , Flag <?>> domainFlags = configuration .getOrDefault (annotation .domain (), new HashMap <>());
38
+
39
+ Arrays .stream (annotation .value ())
40
+ .filter (flag -> !domainFlags .containsKey (flag .name ()))
41
+ .forEach (flag -> {
42
+ Flag .FlagBuilder <?> builder = generateFlagBuilder (flag );
43
+ domainFlags .put (flag .name (), builder .build ());
44
+ });
45
+ addTypedFlags (
46
+ annotation ,
47
+ domainFlags ,
48
+ nonTypedFlagNamesByDomain .getOrDefault (annotation .domain (), new HashSet <>()));
49
+ configuration .put (annotation .domain (), domainFlags );
50
+ });
38
51
return configuration ;
39
52
}
40
53
54
+ private static Map <String , Set <String >> getFlagNamesByDomain (List <OpenFeature > openFeatureList ) {
55
+ return openFeatureList .stream ()
56
+ .map (o -> {
57
+ Set <String > flagNames = Arrays .stream (o .value ())
58
+ .map (dev .openfeature .contrib .tools .junitopenfeature .Flag ::name )
59
+ .collect (Collectors .toSet ());
60
+ return new AbstractMap .SimpleEntry <>(o .domain (), flagNames );
61
+ })
62
+ .collect (Collectors .toMap (Map .Entry ::getKey , Map .Entry ::getValue , (t1 , t2 ) -> {
63
+ t1 .addAll (t2 );
64
+ return t1 ;
65
+ }));
66
+ }
67
+
68
+ private static void addTypedFlags (OpenFeature annotation , Map <String , Flag <?>> domainFlags , Set <String > flagNames ) {
69
+ addBooleanFlags (Arrays .stream (annotation .booleanFlags ()), domainFlags , flagNames );
70
+ addStringFlags (Arrays .stream (annotation .stringFlags ()), domainFlags , flagNames );
71
+ addIntegerFlags (Arrays .stream (annotation .integerFlags ()), domainFlags , flagNames );
72
+ addDoubleFlags (Arrays .stream (annotation .doubleFlags ()), domainFlags , flagNames );
73
+ }
74
+
75
+ private static void addBooleanFlags (
76
+ Stream <BooleanFlag > booleanFlags , Map <String , Flag <?>> domainFlags , Set <String > flagNames ) {
77
+
78
+ booleanFlags .forEach (flag -> addFlag (domainFlags , flagNames , flag .name (), flag .value ()));
79
+ }
80
+
81
+ private static void addStringFlags (
82
+ Stream <StringFlag > stringFlags , Map <String , Flag <?>> domainFlags , Set <String > flagNames ) {
83
+ stringFlags .forEach (flag -> addFlag (domainFlags , flagNames , flag .name (), flag .value ()));
84
+ }
85
+
86
+ private static void addIntegerFlags (
87
+ Stream <IntegerFlag > integerFlags , Map <String , Flag <?>> domainFlags , Set <String > flagNames ) {
88
+ integerFlags .forEach (flag -> addFlag (domainFlags , flagNames , flag .name (), flag .value ()));
89
+ }
90
+
91
+ private static void addDoubleFlags (
92
+ Stream <DoubleFlag > doubleFlags , Map <String , Flag <?>> domainFlags , Set <String > flagNames ) {
93
+ doubleFlags .forEach (flag -> addFlag (domainFlags , flagNames , flag .name (), flag .value ()));
94
+ }
95
+
96
+ private static <T > void addFlag (
97
+ Map <String , Flag <?>> domainFlags , Set <String > domainFlagNames , String flagName , T value ) {
98
+ if (domainFlagNames .contains (flagName )) {
99
+ throw new IllegalArgumentException ("Flag with name " + flagName + " already exists. "
100
+ + "There shouldn't be @Flag and @" + value .getClass ().getSimpleName () + "Flag with the same name!" );
101
+ }
102
+
103
+ if (domainFlags .containsKey (flagName )) {
104
+ return ;
105
+ }
106
+ Flag .FlagBuilder <Object > builder =
107
+ Flag .builder ().variant (String .valueOf (value ), value ).defaultVariant (String .valueOf (value ));
108
+ domainFlags .put (flagName , builder .build ());
109
+ }
110
+
41
111
private static Map <String , Map <String , Flag <?>>> handleSimpleConfiguration (ExtensionContext extensionContext ) {
42
112
Map <String , Map <String , Flag <?>>> configuration = new HashMap <>();
43
113
String defaultDomain = PioneerAnnotationUtils .findClosestEnclosingAnnotation (
44
114
extensionContext , OpenFeatureDefaultDomain .class )
45
115
.map (OpenFeatureDefaultDomain ::value )
46
116
.orElse ("" );
47
- PioneerAnnotationUtils .findAllEnclosingRepeatableAnnotations (
48
- extensionContext , dev .openfeature .contrib .tools .junitopenfeature .Flag .class )
49
- .forEachOrdered (flag -> {
50
- Map <String , Flag <?>> domainFlags = configuration .getOrDefault (defaultDomain , new HashMap <>());
51
- if (!domainFlags .containsKey (flag .name ())) {
52
- Flag .FlagBuilder <?> builder = generateFlagBuilder (flag );
53
- domainFlags .put (flag .name (), builder .build ());
54
- configuration .put (defaultDomain , domainFlags );
55
- }
56
- });
117
+ Map <String , Flag <?>> domainFlags = configuration .getOrDefault (defaultDomain , new HashMap <>());
118
+ List <dev .openfeature .contrib .tools .junitopenfeature .Flag > flagList =
119
+ PioneerAnnotationUtils .findAllEnclosingRepeatableAnnotations (
120
+ extensionContext , dev .openfeature .contrib .tools .junitopenfeature .Flag .class )
121
+ .collect (Collectors .toList ());
122
+ Set <String > flagNames = flagList .stream ()
123
+ .map (dev .openfeature .contrib .tools .junitopenfeature .Flag ::name )
124
+ .collect (Collectors .toSet ());
125
+
126
+ flagList .forEach (flag -> {
127
+ if (!domainFlags .containsKey (flag .name ())) {
128
+ Flag .FlagBuilder <?> builder = generateFlagBuilder (flag );
129
+ domainFlags .put (flag .name (), builder .build ());
130
+ configuration .put (defaultDomain , domainFlags );
131
+ }
132
+ });
133
+
134
+ Stream <BooleanFlag > booleanFlags =
135
+ PioneerAnnotationUtils .findAllEnclosingRepeatableAnnotations (extensionContext , BooleanFlag .class );
136
+ addBooleanFlags (booleanFlags , domainFlags , flagNames );
137
+
138
+ Stream <StringFlag > stringFlags =
139
+ PioneerAnnotationUtils .findAllEnclosingRepeatableAnnotations (extensionContext , StringFlag .class );
140
+ addStringFlags (stringFlags , domainFlags , flagNames );
141
+
142
+ Stream <IntegerFlag > integerFlags =
143
+ PioneerAnnotationUtils .findAllEnclosingRepeatableAnnotations (extensionContext , IntegerFlag .class );
144
+ addIntegerFlags (integerFlags , domainFlags , flagNames );
145
+
146
+ Stream <DoubleFlag > doubleFlags =
147
+ PioneerAnnotationUtils .findAllEnclosingRepeatableAnnotations (extensionContext , DoubleFlag .class );
148
+ addDoubleFlags (doubleFlags , domainFlags , flagNames );
149
+
150
+ if (!domainFlags .isEmpty ()) {
151
+ configuration .put (defaultDomain , domainFlags );
152
+ }
57
153
58
154
return configuration ;
59
155
}
0 commit comments