-
Notifications
You must be signed in to change notification settings - Fork 115
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
Empty values option 2 #445
Conversation
Can one of the admins verify this patch? |
1 similar comment
Can one of the admins verify this patch? |
6184efc
to
a36f495
Compare
Before moving the PR out of draft:
|
@dmlloyd You need to sort your ECA. The other thing - can you associate this PR with an issue. It might be better to open an issue to clearly specify the problem. It might make sense to copy some statement from PRs. When we release, we list issues. The closed unmerged PRs will be discarded. |
ECA is sorted. I'll open an issue. |
| `" "` | `String` | `getOptionalValue` | `Optional.of(" ")` | ||
| `"foo"` | `String` | `getOptionalValue` | `Optional.of("foo")` | ||
| missing | `String[]` | `getOptionalValue` | `Optional.empty()` | ||
| `""` | `String[]` | `getOptionalValue` | `Optional.empty()` |
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.
Some comment applies here that I added under #444,
https://github.com/eclipse/microprofile-config/pull/444/files/#r322320335
a36f495
to
74a8c9f
Compare
This approach is closer to what we have in master. With this, I think it might make better sense just deleting the snapshot and then reserve the copyright. It is not right to use the original idea but remove the original contribution. All contributors are listed under ConfigAccessor needs to be added. I think it is cleaner to delete unwanted methods and then rework. In this case, we can move faster and there won't be any copyright complication. Thoughts? |
@dmlloyd You need to use -s to sign off. "David Lloyd (david.lloyd@****.com) did not include the "Signed-off-by footer" which is required for all commits made by a contributor." |
The original accessor was builder-based and doesn't share a lot of similarities with the original in usage AFAICT. But I'm fine with adding contribution info, if the original author(s) of the original accessor approach want it. I'll add the sign-off once the checklist above is complete. |
I have a plausible implementation of the accessor API here: https://github.com/dmlloyd/smallrye-config/tree/accessor so that should be sufficient to demonstrate the workability of the API. |
Also I don't like how the spec language is a bit inconsistent so I'll probably add commits to clean that up, either as part of this or as a separate PR. But I've filed #447 in any event. |
I've updated this version (locally) to rename |
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 suggest to use the original builder pattern. @struberg please comment.
* @throws IllegalStateException if the accessor is optional, or if the accessor is already associated with a | ||
* type-specific default value, or if there is no converter available for the given type | ||
*/ | ||
<U> ConfigAccessor<U> convertedForType(Class<U> clazz) throws IllegalStateException; |
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 this pattern leads to the creation of ConfigAccessor being mutable or thrown away ConfigAccessor. This is why we introduced the builder pattern in the first place.
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 would expect a properly tuned JDK to elide the vast majority of these allocations or else detect that they do not escape. The config accessor is not mutable (by specification) so I'm not sure what you mean by saying it's mutable.
The "fluent" style of API is widely used already. Using a builder on the other hand is much more unwieldy from a user's perspective, for something that will be thrown away immediately.
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.
Here are some other things to consider:
- Using the fluent immutable API means the result is perfectly type safe. The builder approach means that no mutations are allowed which would change the type of the result (otherwise ugly tricks like unsafely re-typing the object would have to be employed). If (with the builder approach) you forbid re-typing, the type or converter must be passed in to
access
and cannot be changed later; this also means the accessor result must have separate methods for every result type (for example, optional values would need their own method, as would collection values (if those were ever added), etc.). - Using the builder API, you end up with an extra, strange
build
step. These two things together make the API more clunky and decrease its flexibility:config.access("some.prop", Foo.class).build().getOptionalValue()
versusconfig.access("some.prop").withType(Foo.class).optional().getValue()
. It's not entirely obvious that to the user that callingbuild
is necessary, whereas with the immutable option, IDE completion would make it clear what operations are possible in a fairly unambiguous way based on the result type and possible method completions. - The fluent immutable API also reflects the immutability of the
config
object itself (not reflecting the mutability of the backing data, but the actual configuration object and its configuration from an API perspective).
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 agree with David, this pattern is fine and make things type safe and consistent.
cs = config.access("some.prop").withType(Foo.class).WithDefault("blah")
cs.getValue() -> "blah"
cs.WithDefault("Yes!") // <- this does not mutate the cs instance
cs.getValue() -> "blah"
// If users want to provide another default, he has to take the returned ConfigAccessor:
cs.withDefault("Yes!").getValue() -> "Yes!"
In most cases, users won't even keep a reference on the ConfigAccessor
and will directly take the returned value for getValue()
.
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's very similar to the original design and mixes up builder and ConfigAccessor. It's basically the old ConfigValue. We have been there over a year ago.
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 prefer the builder pattern, which was in the master before. With the build pattern, the usage will be a functional style. You build one configAccessor and use it.
* [Spec] add section explaining how the Config API handles a config property with missing or empty value * [Spec] mention that it is possible to set an empty value to reset a property from a lower-ordinal config source. * [TCK] add EmptyConfigPropertyTest to test all cases of empty config property Co-authored-by: David M. Lloyd <david.lloyd@redhat.com>
Signed-off-by: David M. Lloyd <david.lloyd@redhat.com>
74a8c9f
to
944c951
Compare
@dmlloyd This is very, very similar approach to what was originally proposed over 3 years ago. The design is derived from the work we've done in Apache DeltaSpike in 2011 |
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 the better approach is to use builder pattern. In this way, it is nice and clean. Just get hold of a builder and build an accessor. When building it, you can use different default or Converter.
@struberg The current code was influenced by the previous ConfigAccessor code, which was derived from the ConfigJSR conversation (DeltaSpike influcences). |
So I assume this means you don't have any objections to this approach.
One difference I see here is that it uses unsafe casting to use the same mutable instance, as opposed to returning a new typesafe instance.
Yes, this is very similar to my proposed approach. |
Plan is to reopen this as new issues under the new organizational scheme. |
This is the second option for an API to support the new consistent rules for empty value handling, by creating a fluent accessor API instead of using method overloads. Supercedes #407. Fixes #446.