Skip to content

Commit aaf0e0c

Browse files
authored
Map injection behavior restored (3.x) (helidon-io#4653)
* Map injection behavior restored to original (pre helidon-io#1721). Injecting without explicit key will inject all properties, injecting with a key will inject properties where keys have the prefix removed (and only containing keys that are prefixed with the key). Signed-off-by: Tomas Langer <tomas.langer@oracle.com>
1 parent 00c4704 commit aaf0e0c

2 files changed

Lines changed: 75 additions & 9 deletions

File tree

microprofile/config/src/main/java/io/helidon/microprofile/config/ConfigCdiExtension.java

Lines changed: 41 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@
7070

7171
/**
7272
* Extension to enable config injection in CDI container (all of {@link io.helidon.config.Config},
73-
* {@link org.eclipse.microprofile.config.Config} and {@link ConfigProperty}).
73+
* {@link org.eclipse.microprofile.config.Config} and {@link ConfigProperty} and {@link ConfigProperties}).
7474
*/
7575
public class ConfigCdiExtension implements Extension {
7676
private static final Logger LOGGER = Logger.getLogger(ConfigCdiExtension.class.getName());
@@ -248,10 +248,19 @@ private Object produce(InjectionPoint ip) {
248248
+ " container initialization. This will not work nicely with Graal native-image");
249249
}
250250

251-
return produce(configKey, ip.getType(), defaultValue(annotation));
251+
return produce(configKey, ip.getType(), defaultValue(annotation), configKey.equals(fullPath.replace('$', '.')));
252252
}
253253

254-
private Object produce(String configKey, Type type, String defaultValue) {
254+
/*
255+
* Produce configuration value from injection point.
256+
*
257+
* @param configKey actual configuration key to find
258+
* @param type type of the injected field/parameter
259+
* @param defaultValue default value to be used
260+
* @param defaultConfigKey whether the configKey is constructed from class name and field
261+
* @return produced value to be injected
262+
*/
263+
private Object produce(String configKey, Type type, String defaultValue, boolean defaultConfigKey) {
255264
/*
256265
Supported types
257266
group x:
@@ -287,15 +296,19 @@ any java class (except for parameterized types)
287296
}
288297
}
289298

290-
Object value = configValue(config, fieldTypes, configKey, defaultValue);
299+
Object value = configValue(config, fieldTypes, configKey, defaultValue, defaultConfigKey);
291300

292301
if (value == null) {
293302
throw new NoSuchElementException("Cannot find value for key: " + configKey);
294303
}
295304
return value;
296305
}
297306

298-
private Object configValue(Config config, FieldTypes fieldTypes, String configKey, String defaultValue) {
307+
private Object configValue(Config config,
308+
FieldTypes fieldTypes,
309+
String configKey,
310+
String defaultValue,
311+
boolean defaultConfigKey) {
299312
Class<?> type0 = fieldTypes.field0().rawType();
300313
Class<?> type1 = fieldTypes.field1().rawType();
301314
Class<?> type2 = fieldTypes.field2().rawType();
@@ -307,6 +320,7 @@ private Object configValue(Config config, FieldTypes fieldTypes, String configKe
307320
// generic declaration
308321
return parameterizedConfigValue(config,
309322
configKey,
323+
defaultConfigKey,
310324
defaultValue,
311325
type0,
312326
type1,
@@ -371,6 +385,7 @@ private static <T> T convert(String key, Config config, String value, Class<T> t
371385

372386
private static Object parameterizedConfigValue(Config config,
373387
String configKey,
388+
boolean defaultConfigKey,
374389
String defaultValue,
375390
Class<?> rawType,
376391
Class<?> typeArg,
@@ -382,6 +397,7 @@ private static Object parameterizedConfigValue(Config config,
382397
return Optional
383398
.ofNullable(parameterizedConfigValue(config,
384399
configKey,
400+
defaultConfigKey,
385401
defaultValue,
386402
typeArg,
387403
typeArg2,
@@ -395,17 +411,23 @@ private static Object parameterizedConfigValue(Config config,
395411
} else {
396412
return (Supplier<?>) () -> parameterizedConfigValue(config,
397413
configKey,
414+
defaultConfigKey,
398415
defaultValue,
399416
typeArg,
400417
typeArg2,
401418
typeArg2);
402419
}
403420
} else if (Map.class.isAssignableFrom(rawType)) {
421+
// config key we have should serve as a prefix, and the properties should have it removed
422+
// similar to what the original io.helidon.config.Config.get(configKey).detach()
404423
Map<String, String> result = new HashMap<>();
405424
config.getPropertyNames()
406425
.forEach(name -> {
407-
// workaround for race condition (if key disappears from source after we call getPropertyNames
408-
config.getOptionalValue(name, String.class).ifPresent(value -> result.put(name, value));
426+
if (defaultConfigKey || name.startsWith(configKey)) {
427+
String key = removePrefix(configKey, defaultConfigKey, name);
428+
// workaround for race condition (if key disappears from source after we call getPropertyNames)
429+
config.getOptionalValue(name, String.class).ifPresent(value -> result.put(key, value));
430+
}
409431
});
410432
return result;
411433
} else if (Set.class.isAssignableFrom(rawType)) {
@@ -416,6 +438,18 @@ private static Object parameterizedConfigValue(Config config,
416438
}
417439
}
418440

441+
private static String removePrefix(String prefix, boolean defaultConfigKey, String key) {
442+
if (defaultConfigKey) {
443+
return key;
444+
}
445+
446+
String intermediate = key.substring(prefix.length());
447+
if (intermediate.startsWith(".")) {
448+
return intermediate.substring(1);
449+
}
450+
return intermediate;
451+
}
452+
419453
static String[] toArray(String stringValue) {
420454
String[] values = SPLIT_PATTERN.split(stringValue, -1);
421455

microprofile/config/src/test/java/io/helidon/microprofile/config/MpConfigInjectionTest.java

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
import java.lang.annotation.Retention;
2020
import java.lang.annotation.Target;
21+
import java.util.Map;
2122

2223
import io.helidon.microprofile.config.Converters.Ctor;
2324
import io.helidon.microprofile.config.Converters.Of;
@@ -37,6 +38,7 @@
3738
import static java.lang.annotation.ElementType.TYPE;
3839
import static java.lang.annotation.RetentionPolicy.RUNTIME;
3940
import static org.hamcrest.MatcherAssert.assertThat;
41+
import static org.hamcrest.Matchers.hasEntry;
4042
import static org.hamcrest.Matchers.is;
4143
import static org.junit.jupiter.api.Assertions.assertAll;
4244

@@ -59,7 +61,29 @@ class MpConfigInjectionTest {
5961
private SubBean subBean;
6062

6163
@Test
62-
public void testImplicitConversion() {
64+
void testInjectMapNoPrefix() {
65+
Map<String, String> allProperties = bean.allProperties;
66+
assertAll(
67+
() -> assertThat(allProperties, hasEntry("inject.of", "of")),
68+
() -> assertThat(allProperties, hasEntry("inject.valueOf", "valueOf")),
69+
() -> assertThat(allProperties, hasEntry("inject.parse", "parse")),
70+
() -> assertThat(allProperties, hasEntry("inject.ctor", "ctor"))
71+
);
72+
}
73+
74+
@Test
75+
void testInjectMapWithPrefix() {
76+
Map<String, String> injectProperties = bean.injectProperties;
77+
assertAll(
78+
() -> assertThat(injectProperties, hasEntry("of", "of")),
79+
() -> assertThat(injectProperties, hasEntry("valueOf", "valueOf")),
80+
() -> assertThat(injectProperties, hasEntry("parse", "parse")),
81+
() -> assertThat(injectProperties, hasEntry("ctor", "ctor"))
82+
);
83+
}
84+
85+
@Test
86+
void testImplicitConversion() {
6387
assertAll("Implicit conversion injection",
6488
() -> assertThat("of", bean.of, is(Of.of("of"))),
6589
() -> assertThat("valueOf", bean.valueOf, is(ValueOf.valueOf("valueOf"))),
@@ -69,7 +93,7 @@ public void testImplicitConversion() {
6993
}
7094

7195
@Test
72-
public void testImplicitConversionSubclass() {
96+
void testImplicitConversionSubclass() {
7397
assertAll("Implicit conversion injection",
7498
() -> assertThat("of", subBean.of, is(Of.of("of"))),
7599
() -> assertThat("valueOf", subBean.valueOf, is(ValueOf.valueOf("valueOf"))),
@@ -94,6 +118,14 @@ public static class Bean {
94118
@Inject
95119
@ConfigProperty(name = "inject.ctor")
96120
public Ctor ctor;
121+
122+
@Inject
123+
@ConfigProperty(name = "")
124+
public Map<String, String> allProperties;
125+
126+
@Inject
127+
@ConfigProperty(name = "inject")
128+
public Map<String, String> injectProperties;
97129
}
98130

99131
@Qualifier

0 commit comments

Comments
 (0)