NestedJsonProvider: unable to omit empty nested field
Most JsonProviders omit writing their field(s) if their value is null (absent). This is however not the case for the NestedJsonProvider. Consider the following configuration:
<providers>
<nestedField>
<fieldName>nested</fieldName>
<providers>
<mdc/>
</providers>
</nestedField>
</providers>
This configuration produces a JSON similar to the following:
{
"nested": {
"mdc1": "value1",
"mdc2": "value2"
}
}
However when not MDC keys are present or if none matches the include pattern of the MDC json provider, the "nested" object becomes empty and the output looks as follows:
{
"nested": {
}
}
There is unfortunately no option to omit the nested object when it is empty similar to what is available to the PatternJsonProvider.
As proposed in this discussion, an option is to decorate the JsonGenerator to make it filter empty fields. This option would be controlled by a new omitEmptyField configuration property added to the LoggingEventCompositeJsonEncoder. The behaviour would be global and would affect all configured JsonProviders.
Most JsonProvider already omit their fields when they are empty and this behaviour is not configurable (cannot be disabled). Adding a new omitEmptyField global option to the JsonCompositeEncoder may be confusing especially when set to false: people may think that the providers will now output their fields with a null value - which won't be the case unless the implementation is changed.
Instead of adding this feature to the CompositeJsonEncoder we could also limit it to the NestedJsonProvider. In this case the semantic must be clarified:
- should the "nested" field be omitted when its value is empty (i.e. an empty object)
- or do we want this behaviour to propagate to the nested providers as well?
My feeling is when people want to filter out empty properties, they probably want it everywhere and not limited to only a few properties. Adding a global option affecting all properties would be very convenient and easy to understand. I would also enable this option by default and make sure all providers comply to it (i.e. make them output a null value instead of omitting their properties as they do currently if this new property is set to false).
@philsttr What's your opinion?
Hmm. Brainstorming here...
What about having a global omitEmptyFields boolean property on the encoder honored by all providers, but also being able to be overridden on individual providers?
Maybe something like this:
- Add a global
omitEmptyFieldsBoolean property on the encoder, with possible valuestrue,false, and null/unset (the default). - Also add
omitEmptyFieldsBoolean property on the providers as appropriate, with possible valuestrue,false, and null/unset (the default)
The null/unset values mean behave exactly as they do today. And since the default is null/unset, the behavior is fully backwards compatible with how things work today.
When a provider is contributing to the generator,
- if the provider-level value is set, then honor it.
- else if the global-level value is set, then honor it
- else do whatever the current behavior of the provider is ("backwards compatible mode")
Not sure how easy that would be to implement. The providers would need to be able to change the "state" of the token filter before/after the provider contributes to the generator.
My main reasoning for proposing the above is to be able to keep backwards compatibility, while also adding cool new features. Without the null/unset option, and just providing a true/false option, backwards compatibility is broken no matter if the default value is true or false, since neither represents the current behavior. And there would be no way to "revert" to the current behavior.
Alternatively, just implementing a new omitIfEmpty option on the NestedJsonProvider that only applies to the nested object itself (not the sub-providers), with a default value of false, is a much more targetted and simpler approach. I'd be ok doing this as a simple solution first. And then coming back later to try to do the more complex global solution.
As a consumer,
just implementing a new omitIfEmpty option on the NestedJsonProvider that only applies to the nested object itself
would work fine for me. In my normal configuration use case, I'm only adding a single nestedField, so config duplication isn't a concern.