Don't Bail If Optional Property Is Nullified#441
Don't Bail If Optional Property Is Nullified#441karthicks wants to merge 1 commit intolightbend:masterfrom
Conversation
| if (!isOptionalProperty(clazz, beanProp)) { | ||
| // bubble the {@link Missing} exception up | ||
| throw e; | ||
| } |
There was a problem hiding this comment.
Should this (sometimes?) be explicitly setting the field to null? I feel like if the config does not contain a setting, maybe we keep whatever the bean's constructor set, but if the config explicitly has null in it, we should probably explicitly set to null?
| } | ||
| } else { | ||
| try { | ||
| Object unwrapped = getValue( |
There was a problem hiding this comment.
I wonder if it would be better to handle null in getValue (would need to pass in to getValue whether the prop is optional and then use config.getIsNull I think). An advantage would be to avoid exceptions in normal control flow, which is nice because they are legitimately pretty slow to throw, and that could matter to some programs.
There was a problem hiding this comment.
On second thought, would it be acceptable to treat null values as if they were missing, as the spec states? That way, we can avoid exceptions during the normal control flow.
| assertNotNull(beanConfig) | ||
| assertNotNull(beanConfig.getValueObject) | ||
| assertNull(beanConfig.getValueObject.getOptionalValue) | ||
| assertNull(beanConfig.getValueObject.getNullableValue) |
There was a problem hiding this comment.
maybe we could test the matrix of combinations of
- bean constructor sets to null vs non-null
- config explicitly sets to null or simply omits the setting
If only to be sure we don't accidentally change behavior of one of those matrix cells later.
There was a problem hiding this comment.
Currently, we do kind of test the use case where a value is set to null versus a value that is simply missing or omitted. The ObjectsConfig#optionalValue field is being used to test the value being omitted, and the ObjectsConfig#nullableValue field for the value being set to null.
|
thanks for the PR! |
|
@havocp , sorry about the belated response. I tweaked the change so that it doesn't rely on the exception-based approach initially proposed. Can you take a look to see if this is more acceptable? -Karthick |
| } | ||
|
|
||
| public void setNullableValue(String nullableValue) { | ||
| this.nullableValue = nullableValue; |
There was a problem hiding this comment.
I think (could be wrong) that we aren't testing the behavior where the bean constructor sets a non-null value on the optional field, and then either we do not have it in the config, or it's set to null in the config. Intuitively I would think it should be overwritten with null only if explicitly set in the config?
There was a problem hiding this comment.
Though i can see the argument for overwriting it with null always (always ignore the bean constructor) maybe ?
There was a problem hiding this comment.
I think you're right. If an optional field is defaulted (either through an initializer or the default constructor), and if that field is missing in the configuration, then that default value should take effect. That does seem more intuitive to me.
| } | ||
| if (configValue == null && !isOptionalProperty(clazz, beanProp)) { | ||
| SimpleConfig.addMissing(problems, expectedType, path, config.origin()); | ||
| } |
There was a problem hiding this comment.
Does this imply that the throw new ConfigException.Missing a few lines down is now unreachable? If so we might throw a BugOrBrokenException("Should have detected missing props earlier") down there instead of ConfigException.Missing.
|
@havocp , In order to handle fields in the bean that are initialized with a default value, I took the approach you initially suggested, viz., handle null values properly in What do you think? -Karthick |
havocp
left a comment
There was a problem hiding this comment.
Thanks for updating this, I apologize for taking a while to reply.
|
|
||
| final private SimpleConfigOrigin origin; | ||
|
|
||
| private boolean optional; |
There was a problem hiding this comment.
this field won't work for a couple reasons; 1) ConfigValue is immutable, 2) if this was changed to make a copy of the config value, it would still not be conceptually part of the value, it's part of the implied "schema" instead.
will suggest another way to do this below
| // Otherwise, raise a {@link BugOrBroken} exception | ||
| throw new ConfigException.BugOrBroken("Should have detected missing props earlier"); | ||
| } | ||
| Object unwrapped = getValue(clazz, parameterType, parameterClass, config, configPropName); |
There was a problem hiding this comment.
To let this getValue return null, I'd suggest passing in a parameter to getValue optional=true|false, and then at the top of getValue do something like:
if (optional and config.getIsNull(configPropName))
return null;
I think that will work ?
|
Hi @yellowblood, @camullen, Thank you for your contribution! We really value the time you've taken to put this together. Before we proceed with reviewing this pull request, please sign the Lightbend Contributors License Agreement: |
d38fba7 to
2546803
Compare
|
@havocp , Updated the pull request as per your suggestion, which relies on the -Karthick Sankarachary |
| // Otherwise, raise a {@link Missing} exception right here | ||
| throw new ConfigException.Missing(beanProp.getName()); | ||
| // Otherwise, raise a {@link BugOrBroken} exception | ||
| throw new ConfigException.BugOrBroken("Should have detected missing props earlier"); |
There was a problem hiding this comment.
This should be reverted to the original exception, because the related change (which was proposed here) is not in the PR anymore.
There was a problem hiding this comment.
Just saw this comment. Don't know why I didn't get an email notification earlier. In any case, I've reverted to the original exception. Sorry for the belated response.
|
I think this can be merged when the exception type is reverted. |
For details on the problem description, please refer to #440.