Skip to content

Conversation

@antongrbin
Copy link
Contributor

@antongrbin antongrbin commented Oct 25, 2022

Motivation

Fixes #235

Changes

  • Change the behavior for JSON serialization for fields with explicit presence.
  • If unset -> don't emit on the wire.
  • If set -> emit on the wire, even if the value is default (regardless of the jsonConfig.outputDefaultValues)

This is consistent with the following:
https://github.com/protocolbuffers/protobuf/blob/main/docs/field_presence.md#semantic-differences

This PR also changes behavior of outputDefaultValues for unset nested message fields. Before we were outputting null and now we don't output any value. This is consistent with c++, python and java, as explained here: noom/protobuf#5

Tested

Run all unit tests in runtime

assertEquals(JsonPrimitive(TestAllTypesProto3.NestedEnum.fromValue(0).name!!), parsedJson["optionalNestedEnum"])

assertEquals(JsonNull, parsedJson["optionalNestedMessage"])
assertFalse("optionalNestedMessage" in parsedJson)
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I looked deeper into this, please see explanation in PR description about this.


if (value == null && fd.oneofMember) continue
if (!fd.oneofMember && !jsonConfig.outputDefaultValues && fd.type.isDefaultValue(value)) continue
val oneOfOrExplicitPresence = (fd.oneofMember || fd.type.hasPresence)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I remember right, I think fd.type.hasPresence will always be true for oneof fields. So you might be able to simplify this and only test for fd.type.hasPresence and drop the explicit test for fd.oneofMember.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I applied the change, thank you. The tests that we have still pass.

I tried quickly to trace where hasPresence is being set for oneOf fields but I couldn't find it easily :) I would appreciate a pointer so I can better understand what I'm doing :)

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

hasPresence in the generated code is set here:

type == File.Field.Type.ENUM -> "Enum(enumCompanion = $kotlinQualifiedTypeName.Companion" + (if (hasPresence) ", hasPresence = true" else "") + ")"
. That is in turn based on the value of File.Field.Numbered.hasPresence, which is set here during the parsing of the proto files:
hasPresence = (fieldDesc.label != FieldDescriptorProto.Label.REPEATED) &&
. That's where the oneof-related logic is coming from.

@antongrbin antongrbin requested a review from garyp October 25, 2022 20:21
@garyp garyp merged commit 6525f28 into streem:master Oct 25, 2022
garyp pushed a commit that referenced this pull request Mar 7, 2023
…#238)

Fixes #235

* Change the behavior for JSON serialization for fields with explicit presence.
* If unset -> don't emit on the wire.
* If set -> emit on the wire, even if the value is default (regardless of the `jsonConfig.outputDefaultValues`)

This is consistent with the following:
https://github.com/protocolbuffers/protobuf/blob/main/docs/field_presence.md#semantic-differences

This PR also changes behavior of `outputDefaultValues` for unset nested message fields. Before we were outputting `null` and now we don't output any value. This is consistent with c++, python and java, as explained here: noom/protobuf#5

Run all unit tests in `runtime`
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Unexpected 0-th value enum JSON serialization

2 participants