-
Notifications
You must be signed in to change notification settings - Fork 116
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
#240 config properties #565
#240 config properties #565
Conversation
@radcortez @OndroMih please comment |
api/src/main/java/org/eclipse/microprofile/config/inject/ConfigProperties.java
Outdated
Show resolved
Hide resolved
baaedff
to
b0c5409
Compare
Please give you +1 if you are happy with the current change. I'll then add TCKs. Otherwise, please provide feedback asap. |
@radcortez I've added some tcks. Please either leave any feedback or approve. Thanks! |
532100c
to
19970aa
Compare
@Emily-Jiang how about if we also add this to the programatic API? It could work similar as the MP Rest Client Builder. For instance: ConfigBuilder.register(Class) // Interface registration
Config.getConfigProperties(Class) // Interface retrieval |
tck/src/main/java/org/eclipse/microprofile/config/tck/ConfigPropertiesTest.java
Show resolved
Hide resolved
It would be nice if PRs that introduce a new semantic of feature gives a short summary in the description from users perspective. |
api/src/main/java/org/eclipse/microprofile/config/inject/ConfigProperties.java
Show resolved
Hide resolved
@jbee, @Emily-Jiang, I've added a short description to this PR as @jbee suggested just to have something there @Emily-Jiang , feel free to change it as you wish. |
@radcortez I added |
The registration is to avoid to scan the entire classpath for classes annotated with For non-CDI environments, I think manually registration would be better, or implementations will be required to scan the classpath (and may not have code to do it). |
@radcortez, for CDI, it is easy as the In last week's hangout, @struberg @jbee and I discuss this in details. @struberg suggested not to add the api to getConfigProperties. We can use the existing getValue. As for the non-spi, you don't need to preactively process that class. I don't see the reason to register the class. Besides, the registering is done by developers. We can't guarantee whether it will be called. |
Well, I'm not sure if I agree, because we don't seem to be consistent between the CDI API vs non CDI API. Right now, the user experience is already very different and this will be another thing to add to the list. Is there any reason why we shouldn't add |
@radcortez The capability for programmatic usage isn't removed by removing the |
It it a difference user experience, because you are able to create an interface with all your configs and use it directly with CDI. Without CDI you are unable to do it, and you would need to call Like @OndroMih suggested, we could provide a similar functionality as MP REST Client. This not only provide consistency between CDI / non CDI, but also consistency across MP Specs. |
This is a misunderstanding. You will not need to do that. You can do: config.getValue("base.path", MyConfigPropertiesBean.class) which is equivalent to injecting |
Ok, I see, it was not very clear in the comment. In that case, we probably want a Anyway, I think overloading |
I'll add more commit to rectify the tcks with the new update. I'll tidy up the PR shortly. |
We have a few options to choose from, based on the conversation with @radcortez @OndroMih @jbee @struberg . Let me list as follows. Option 1. Create one new annotation
Use the following to look up ServerDetails with provided prefix.
Option 2. same as the previous option but the prefix is fixed. Create one new annotation
Use the following to look up ServerDetails with provided prefix.
Option 3: Create 2 new annotation
Use the following to look up ServerDetails with provided prefix.
Option 4: Create 2 new annotation
Use the following to look up ServerDetails.
Option 2 and 4 are similar to option 1 and 3. Do we think in the lookup logic, we would supply a different suffix? I think it is unlikely. We can then choose either 2 or 4. Once we choose the option, we then decide the annotation names. |
Vote: Option 1 |
Vote: Option 2 |
Vote: Option 3 |
Vote: Option 4 |
For Option 3 and 4, you don't really need an additional annotation to perform injection. Each interface / class is unique, there is only one implementation, so it doesn't need a CDI qualifier. For Option 1 and 2 (that reuses the current |
I don't think we need to choose between specifying a prefix only in
Thus I propose a new Option 5 which basically merges Option 1 and 2, a new Option 6 which merges Option 3 and 4, and, finally, a new Option 7, which merges everything altogether to avoid unexpected behavior as follows: Option 5 With
or
The following looks up
or
Option 6 This option would introduce a new @emilyjiang's Options 3 and 4 suggest that this method is named Then the following looks up
or
The following looks looks up
or
Option 7 This option is basically the Option 6 but also supports what's proposed in Option 5 for users that might find it more natural. The reason is to avoid that users get confused when trying to use Then, retrieving
The usage of |
As mentioned earlier, I started with Interface idea and decided against.
I will do a commit to add this, so that we can support both interface and class. Thoughts? |
I am looking at this independent of what might be done or standard elsewhere. From that perspective I find interfaces a mismatch. Methods suggest the values might change when they will not. To implement it a proxy or dynamic class generation hammer needs to be utilised potentially making dynamic computations for something that never changes. With CDI scope annotation present in your example I wonder if the bean would be a full CDI bean with all consequences meaning the methods could actually return different values due to some interceptor magic which I again would find a mismatch with the nature of data that never changes. |
@jbee I don't think interface suggests the values might change though as there is no way to set the property in the interface. As for implementation, I think it is pretty much similar to Class implementation. You just need to create instances for it, similar to Rest Client. Having this said, since we might not easily reach consensus on the interface flavour, I would like solve all issues on the class flavour first and then start working on interface so that further comments can be added and discussed more thoroughly. By the way, @OndroMih is pretty much keen for interface support. @OndroMih can you please comment? As for the CDI Bean, when the instance injection happens, the instance is pretty much baked. Invoking the method on the bean should give you the same value. If you inject a Provider<>, you will get a proxy. |
@Emily-Jiang I try to make my point more clear: Interfaces don't suggest anything but methods do and interfaces must use methods. Its not an opinion but a fact of the Java language that methods exist to give access to a value that is bound to change. Therefore using interfaces suggests the information isn't information but behaviour which means it might change on you. If the information is indeed information there are features in the language to express that and I only suggest to use them. |
Signed-off-by: Emily Jiang <[email protected]>
cb3e3e2
to
8127e34
Compare
I am ok to start with class first. We can always consider interface later if enough people ask for it. One might be enough as they are similar. Spring Config chooses class while Deltaspike config choose interface flavour. |
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.
Hi @Emily-Jiang and all, the PR now looks good to me. I agree that using interfaces is a bit more cumbersome than classes and doesn't add much more value in this case. It's still true that the API proposed right now differs from the REST client API but I understand they serve a different purpose and there's no need to match the APIs exactly. I agree that we can add support for interfaces later but their value is mostly in providing support for values that change dynamically, in the same way as @Inject Instance
supports now already. After reviewing all the conversation now I think that the additional complexity isn't worth it and we should just support classes.
I only have one comment about the requirement for zero-arg constructors. As I commented at the code level, I disagree with enforcing that the implemenation must raise an exception in case of zero-arg constructors. The spec should instead encourage using zero-arg constructors but not forbid them. Implementations may be able to support classes without zero-arg constructors and even build custom features around them, there's really no reason to limit the implementations by forcing to throw an exception.
tck/src/main/java/org/eclipse/microprofile/config/tck/broken/ConfigPropertiesZeroArgPL.java
Outdated
Show resolved
Hide resolved
Signed-off-by: Emily Jiang <[email protected]>
I think this is a good compromise to communicate to the user what is expected of the class used to be portable. If a vendor supports other scenarios these are clearly communicated as non-portable. |
Signed-off-by: Emily Jiang <[email protected]>
@jbee @OndroMih Thanks for your approval! Please have a double check to see whether the final one is good. @radcortez please check whether all of your comments are address. If yes, please approve this PR. |
Signed-off-by: Emily Jiang <[email protected]>
@radcortez I think I have addressed all of your comments! Can you double check and approve as I would like to merge this PR today based on our last week's conversation? |
Signed-off-by: Emily Jiang <[email protected]>
@jbee @radcortez further to our meeting conversation, I have added AnnotationLiteral support. The PR is complete. Please review and approve if you have no further comments! Thanks |
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.
Just added one comment for consideration.
api/src/main/java/org/eclipse/microprofile/config/inject/ConfigProperties.java
Show resolved
Hide resolved
@radcortez can you do a final review as I think all of your requests were addressed? As mentioned in our hangout last week, I would like to merge this last week. It will be good if we can merge it today. |
api/src/main/java/org/eclipse/microprofile/config/inject/ConfigProperties.java
Outdated
Show resolved
Hide resolved
api/src/main/java/org/eclipse/microprofile/config/inject/ConfigProperties.java
Outdated
Show resolved
Hide resolved
api/src/main/java/org/eclipse/microprofile/config/inject/ConfigProperties.java
Outdated
Show resolved
Hide resolved
* If the prefix is null, this method is equivalent to {@linkplain #getConfigProperties(Class)}. | ||
* @return An instance for the specified type and prefix | ||
*/ | ||
<T> T getConfigProperties(Class<T> configProperties, String prefix); |
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.
Considering the last sentence of the javadoc:
If the prefix is null, this method is equivalent to {@linkplain #getConfigProperties(Class)}.
Shouldn't <T> T getConfigProperties(Class<T> configProperties);
be implemented as a default method that calls getConfigProperties(Class<T> configProperties, null)
?
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.
yes
* If the `prefix` is absent, the field `x` maps to the property name `x`. | ||
|
||
If the field name `x` needs to be different from the config property name `y`, use `@ConfigProperty(name="y")` to perform the transformation. | ||
If the prefix is present, the field `x` maps to the configuration property `<prefix>.y`, otherwise `y`. |
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.
I think we need to define a few more mapping rules. For instance, a dash -
, is a valid char to be part of the name of a configuration property. How do you map them to method names? Or should we consider that there is no convention to map these and you always have to rely on the annotation to set the name?
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.
I am confused, isn't the mapping the other way around? The field name maps to a property, and as you can use all valid field names as property names this is fine. Or if you annotate the field and provide a string for name the name can be any string which should make any valid property name work.
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 is tricky for the mapping rules as when we might have to look up client.name, client_name, client$name based on some mapping rules. Which one to match first? It will be very messy. Since the config property always rely on names to specify property names, we use the same approach. I suddently thought of something in this area. Should we force prefix to contain all characters? At the moment, we added dot between prefix and the rest part. I think it is better not to add dot as there might be other separator such as _ used in the config properties such as client_name, client_age.
Thoughts? @radcortez @jbee If you agree, I will update the last bit.
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.
I am happy either way. Implicit dot is more constrained but maybe a bit more intuitive, explicit is more flexible but also a bit less intuitive to me.
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.
I think it is nice to make prefix as the prefix without adding arbitratry separator. I have done the changes accordingly. Please double check again as I aim to merge this PR asap.
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.
Not sure if I agree with this. It may cause additional issues if we want to support nested / subnamespaces.
Still, this doesn't address the original comment. For instance if I have the following property:
foo-bar=baz
There is no way I can express that in a method name, unless I use the annotation to set the name. For instance Spring uses these rules for binding: https://docs.spring.io/spring-boot/docs/current/reference/html/spring-boot-features.html#boot-features-external-config-relaxed-binding
Meaning that a method with the name fooBar
could bind to the property fooBar
or foo-bar
, or foo_bar
or FOOBAR
.
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.
I think for the prefix it allows for all characters. We don't need to transform it and keep it as exact. I prefer to use the exact prefix without adding the additional dot as the prefix might be ending with $ or - or _.
I was thinking not to transform the field but using `ConfigProperty(name="") to specify the exact name. As for environment variable mapping, we have defined the rules already, which is to transforming all illegal characters to _ and then try to search all uppercase.
Let's explore a bit more on the support of mapping. @radcortez I think one of the possible tranformation is to translate . or - character to _
foo-bar=baz
matches to the field foo_bar
.
However, when we search for config properties, we need to state foo_bar can match foo_bar, foo-bar, foo.bar in this order. It is a kind of messy. I am not sure. Using ConfigProperty
might be much cleaner. I think for the first version, we just support the exact match and then adding the relaxation rule based on feedback.
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 is fine by me, I just wanted to add the clarification saying that we only support exact match or @ConfigProperty
name, so people don't expect any kind of mapping rules.
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.
ok thanks @radcortez ! I'll merge my PR now.
@Emily-Jiang added some review comments to fix some typos. I did approve it the PR, but I think we need to clarify this: #565 (comment) /cc @jbee |
Signed-off-by: Emily Jiang <[email protected]>
Signed-off-by: Emily Jiang <[email protected]>
@jbee @radcortez I have done the final tidy up with prefix. Please cast your eyes over for the final time and then we are good to go. I appreciate your early repsonse. Thank you! |
A proposal to group properties that share the same prefix into a single class or interface to introduce "type-safe" property access and also reduce the boiler-plate code to access those properties.