-
Notifications
You must be signed in to change notification settings - Fork 119
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 a fixed list of Map keys statically @WithKeys #1220
Conversation
*/ | ||
@Documented | ||
@Retention(RetentionPolicy.RUNTIME) | ||
@Target({ ElementType.METHOD, ElementType.TYPE_USE }) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It should only be TYPE_USE
IMO. The other cases where we have both are historical (IIRC) where it was wrongly METHOD
but we actually intended it to be TYPE_USE
. Having both means we have to check for it twice in very different ways, which is sometimes quite painful.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sure, this was to make it consistent with the other annotations.
So from what I understand this is how it's supposed to be used: @ConfigMapping(prefix = "map")
interface KnownMapKeys {
@WithKeys({ "one", "two" })
Map<String, String> values();
} I am unsure what the use case is, since it seems to me that removing @ConfigMapping(prefix = "map")
interface KnownMapKeys {
@WithDefaults
Map<String, String> values();
} Or is it just to mandate the keys interface MyStaticMap {
String one();
String two();
}
@ConfigMapping(prefix = "map")
interface KnownMapKeys {
MyStaticMap values();
} Anyway, I don't have anything against it in principle, I think I'm just missing the point. |
Yes, sorry, I was not very clear in the goal. One motivation is to provide the static set of keys during build time for runtime. Of course, this cannot be done by a plain array of keys in the annotation, so that is why we have a class provider https://github.com/smallrye/smallrye-config/pull/1220/files#diff-8f82c482208ee092deabd66a10cfc069c895fc0b95a2d8ca92d5b0751e3b5e52R23. The intent is that this provider can be generated during build time for cases where we can determine the list of keys, but at the same time, the keys are dynamic enough that they cannot be typed statically in the mapping. As an example, check the REST Client configuration: We need to map the REST Client configuration as a
I think this is definetely useful for the REST Client case and also in another similar case with OTel. I was wondering if you would find this useful for datasources or hibernate. |
Thanks, that's clearer. I agree this makes a lot of sense.
This example seems a bit weird though... it seems it allows two different keys (class name and client name) to configure the same client. And I think that is the reason for I think to solve the problem in the rest client, what you'd need instead (or on top) of this PR would be some concept of "synonym" keys? Then Smallrye Config would be able to merge configs using keys that refer to the same client (and/or to fail on conflicts), and the Rest Client extension would retrieve the config more naturally, without having to check for mandatory properties.
For "required checks" I'm not sure, first because I don't see how it helps (see ^), and second because required config is quite rare. To "report as unused / unknown keys that are not part of the list", definitely -- though I'm not sure this will be a high-priority change in the Hibernate extensions, sorry -- our todo list is long :) It's more of a "nice-to-have". For "sources that do not provide a list of property names", I've never faced the issue personally, but it makes sense -- it will probably help for Hibernate/datasources as well. |
Yes, the REST Client config is a bit of a mess. We added the convention where we use the FQN of the class, simple name, or
We already do that with fallbacks
The Thanks for the feedback. I think we agree that this is useful, so I'll complete the missing pieces. |
If by "fallbacks" you mean what's implemented in the REST client, well... it's not quite the same, as it's the extension doing all the heavy lifting. And it prevents one from defining mandatory properties. What I meant is this: @ConfigMapping(prefix = "some-config")
interface SomeConfig {
@WithDefaults
@WithFallbackKeys(provider = MyProvider.class)
Map<String, String> values();
}
class MyProvider implements FallbackKeyProvider {
public List<String> getFallbackKeys(String requestedKey) {
return switch(requestedKey) {
case "myClient1": yield List.of("com.acme.ClientInterface1");
case "myClient2": yield List.of("com.acme.ClientInterface2");
};
}
} Which would lead to this: SomeConfig config = ...;
config.get("myClient1"); // returns config set with key "myClient1" OR "com.acme.ClientInterface1", merged.
The
The only reason you're not getting validation in the "rest client" case is that
Fine by me, but before going further I'd warmly recommend you write an actual test to check that this solves the Rest Client problem (the "making keys required" problem you mentioned when you linked to https://github.com/quarkusio/quarkus/blob/39d5ba15c056d67968c30a7cc5f050708895a860/extensions/resteasy-classic/resteasy-client/runtime/src/main/java/io/quarkus/restclient/runtime/RestClientBase.java#L305-L320). Because it seems to me this won't solve it. Or, possibly, I'm completely misunderstanding what's going on :) |
No, it is done in config directly: All the
In practice a That makes sense when you don't know how to populate the
For sure, I wouldn't be doing it in any other way :) |
Okay, that... was unexpected. Thanks for explaining.
Would it still be possible when using |
Correct. That is something we can add. When I made the initial move, it was not only a plain root -> mapping migration. The REST Client config had its own implementation to retrieve values, disregarding the root completely (only used for documentation). I've tried to be conservative with the changes, and we still had compatibility issues. Things should be more stable now, and I think we can be more confident with further code changes by getting rid of things we don't need, optimizing the lookups, and adequately setting up the mapping structure. Thank you for all the feedback. It is very useful :) |
8e47fc1
to
4325186
Compare
This is how the REST Client changes look like: There are still two gaps not related to this new feature (that I plan to address later):
|
Add a new annotation
@WithKeys
to be used withMap
in@ConfigMapping
.The purpose is to provide a list of keys to populate the
Map
instead of relying on the list of property names (which may not include all the defined keys in the configuration).Inspired by