Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support for properties with dynamic names #991

Closed
wants to merge 1 commit into from
Closed

Conversation

ejba
Copy link

@ejba ejba commented Sep 3, 2023

Fixes #986

Copy link
Member

@radcortez radcortez left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @ejba! Thank you very much for the PR. Highly appreciated.

While the original issue is reported against the YAML source, the problem is not in the YAML source implementation but in how the overall mechanism of multiple profiles is implemented.

The current approach works fine for non-dynamic lookups. The problem is when mapping a Map, the config system has to rely on the list of property names available to discover the dynamic key to place in the Map. If the list of property names does not contain the desired property in the active profile, the config system cannot discover it and the mapping will either fail or not map at all.

I believe a better fix may be provided in ProfileConfigSourceInteceptor by rewriting the multiple profile keys to be part of the active profile, which would solve the issue for any configuration source and not just YAML. There is a relocate rule to rewrite the multiple profile keys in SmallRyeConfigBuilder, which may also require some adjustments:

@Override
public ConfigSourceInterceptor getInterceptor(final ConfigSourceInterceptorContext context) {
Map<String, String> relocations = new HashMap<>();
relocations.put(SmallRyeConfig.SMALLRYE_CONFIG_PROFILE, Config.PROFILE);
List<MultipleProfileProperty> multipleProfileProperties = new ArrayList<>();
Iterator<String> names = context.iterateNames();
while (names.hasNext()) {
String name = names.next();
if (name.length() > 0 && name.charAt(0) == '%') {
NameIterator ni = new NameIterator(name);
String profileSegment = ni.getNextSegment();
List<String> profiles = convertProfile(profileSegment.substring(1));
if (profiles.size() > 1) {
multipleProfileProperties
.add(new MultipleProfileProperty(name, name.substring(profileSegment.length()), profiles));
}
}
}
// Ordered properties by least number of profiles. Priority to the ones with most specific profiles.
for (MultipleProfileProperty multipleProfileProperty : multipleProfileProperties) {
for (String profile : multipleProfileProperty.getProfiles()) {
relocations.putIfAbsent("%" + profile + multipleProfileProperty.getRelocateName(),
multipleProfileProperty.getName());
}
}
return new RelocateConfigSourceInterceptor(relocations);
}

@ejba ejba force-pushed the 986 branch 3 times, most recently from 657b0ca to 7c2d69d Compare September 15, 2023 11:12
@ejba ejba changed the title Support dynamic keys in a map's key (#986) Relocate property keys with multiple profiles Sep 15, 2023
@ejba
Copy link
Author

ejba commented Sep 15, 2023

Hi @radcortez! Thank you with your kind words. I should discuss the solution before opening a PR, apologies.

@ejba ejba changed the title Relocate property keys with multiple profiles Support for properties with dynamic names Sep 15, 2023
@ejba ejba requested a review from radcortez September 16, 2023 12:46
@Test
void multipleProfilesWithDynamicKey() {
SmallRyeConfig config = new SmallRyeConfigBuilder()
.withSources(config(SMALLRYE_CONFIG_PROFILE, "\"%common,prof\"", "config_ordinal", "1000"))
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't expect the profiles to be quoted or include the %. Profiles are usually set as:

smallrye.config.profile=prod
smallrye.config.profile=common,prod
smallrye.config.profile=one,two,three

The % is just to mark that the next name in the configuration property is the profile to be used, but it shouldn't be required when setting the profile.

Did you find a situation where you need the profiles to be quoted?

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, I didn't find any practical example that requires quoting profile names. I will remove this part.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed :)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I believe a better fix may be provided in ProfileConfigSourceInteceptor by rewriting the multiple profile keys to be part of the active profile ...

Looking at your comment, maybe I missed something. Why does ProfileConfigSourceInteceptor need to be changed?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider:

@ConfigMapping
interface MyConfig {
 Map<String, String> foo();
}
foo.bar=baz
%dev.foo.bar=baz
%common,dev.foo.bar=baz

In this case, because the second segment of foo.bar is dynamic (the Map key), we cannot query it directly. We need to iterate the list of property names and find the ones in the Map namespace of foo.

With profiles, I guess we could search the profile namespace too (or multiple ones like in this case). On the other hand, when we added profiles, to not explode the list of property names, or even confuse users with the added prefix, we rewrite profile configuration names in their non-profile version (active):

@Override
public Iterator<String> iterateNames(final ConfigSourceInterceptorContext context) {
final Set<String> names = new HashSet<>();
final Iterator<String> namesIterator = context.iterateNames();
while (namesIterator.hasNext()) {
names.add(normalizeName(namesIterator.next()));
}
return names.iterator();
}

But in the case of multiple profile configuration names, this is not working. I believe that rewriting the multiple property names in their non-profiled format should do the trick (as long as the name found has any of the profiles active).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hey @ejba, how are you? Are you still planning to work on this? Thanks!

@radcortez
Copy link
Member

Closing in favour of #1080.

@radcortez radcortez closed this Jan 8, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Support for properties with dynamic names (e.g. Quarkus' "%dev,test") in Map-based configuration
2 participants