Skip to content
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

Proto2 required fields that contain default values are not serialized correctly #71

Closed
sujithkris opened this issue Jul 14, 2020 · 8 comments · Fixed by #216
Closed
Labels
bug Something isn't working component-codegen question Further information is requested syntax-proto2
Milestone

Comments

@sujithkris
Copy link

sujithkris commented Jul 14, 2020

My proto is as follows

message Update {
    repeated Prop prop = 1;
    message Prop {
        oneof prop_update_type {
            StandardProp standard_prop = 2;
            RegularProp regular_prop = 5;
        }
    message StandardProp {
        optional string id = 1;
        optional string title = 2;
    }

    message RegularProp {
        required string name = 1;
        required bool is_array = 2;
        optional Value value = 3;
    }
}
message Value {
    oneof value {
        string string_value = 1;
        bool boolean_value = 2;
        int32 integer_value = 3;
        int64 long_value = 4;
        float float_value = 5;
        double double_value = 6;
    }
}

The Update object protoMarshal() is sent across Kafka and on the consumer side, I am getting exceptions which are on java platform. The exceptions are different in different projects.

Note: I am getting exception only when Prop contains RegularProp.

Below listed bullet points are the exception messages I am getting in java projects which deserialize using Update.parseFrom(data)

Project - 1
Value cannot cast to Update
Project - 2
prop[0].regular_prop.is_array not present

Is this due to the presence of Value in RegularProp?

The same proto is used by other Kafka producers in different projects (Javascript, java, etc.) and working fine. So to repeat the exception is only for Kafka message sent from Kotlin to other platform and only when using RegularProp

@sujithkris
Copy link
Author

sujithkris commented Jul 14, 2020

Json representation of Update

  • Kotlin updateObject.jsonMarshal()

{"prop":[{"standardProp":null, "regularProp":{"name":"string-key","isArray":false,"value":{"stringValue":"string-value","booleanValue":null,"integerValue":null,"longValue":null,"floatValue":null,"doubleValue":null}}}]}

  • Java JsonFormat.printToString(updateObject)

{"prop": [{"regular_prop": {"name": "string-key", "is_array": false, "value": {"string_value": "string-value"}}}]}

@sujithkris sujithkris changed the title Deserialization Exceptions in java projects. Deserialization Exceptions in apps using java protobuf libs Jul 14, 2020
@garyp
Copy link
Collaborator

garyp commented Jul 15, 2020

I suspect the RegularProp.is_array field is being excluded from the binary serialization because its value is false. This would be the right thing to do in proto3, but not for a required field in proto2. @sujithkris Any chance you can provide the binary data that's being generated by the Kotlin code when this error happens?

@garyp garyp added bug Something isn't working question Further information is requested labels Jul 15, 2020
@sujithkris
Copy link
Author

sujithkris commented Jul 15, 2020

I suspect the RegularProp.is_array field is being excluded from the binary serialization because its value is false. This would be the right thing to do in proto3, but not for a required field in proto2. @sujithkris Any chance you can provide the binary data that's being generated by the Kotlin code when this error happens?

Yes @garyp, Thank you very much for the pointer. It worked with is_array set to true. So you recommend a migration to proto3 or any other approach?

Would you prefer to look into binary data still? I can try to share it.

Just wondering how this works fine between java producer & java consumer and we noted this issue only now when migrating to Kotlin producer! Or I think I need to verify java to java once again whether this false condition really working :)

@garyp
Copy link
Collaborator

garyp commented Jul 15, 2020

@sujithkris This seems like a bug in pbandk. That's why it works in Java 🙂 pbandk isn't doing the correct thing for proto2 required fields that contain default values.

At least that's my hypothesis. If you could share the binary data, that'd help me confirm the hypothesis. But I should be able to also write a quick unit test to test this scenario.

@sujithkris
Copy link
Author

sujithkris commented Jul 16, 2020

@garyp - Good to address the presence of default null in JSON as well, which increases the size of the payload. We can see the null fields does not present in the output of java JsonFormat.printToString(protoObject)

I did not get a chance to get the binary data. Let me know the best way you recommend to share the same.

@garyp
Copy link
Collaborator

garyp commented Jul 22, 2020

Good to address the presence of default null in JSON as well, which increases the size of the payload.

@sujithkris The JSON format is technically defined only for proto3 files. The Javadoc for the Java JsonFormat class says (emphasis added):

The JSON format follows Proto3 JSON specification and only proto3 features are supported. Proto2 only features (e.g., extensions and unknown fields) will be discarded in the conversion.

While the JSON format will mostly work fine with proto2 files, there are going to be proto2-specific corner cases with undefined behavior. I wouldn't recommend using JSON with proto2 files until Google officially supports it.


I did not get a chance to get the binary data. Let me know the best way you recommend to share the same.

It should be pretty small. So you could just base64-encode it and paste it into a comment here.

@sujithkris
Copy link
Author

sujithkris commented Sep 14, 2020

@sujithkris This seems like a bug in pbandk. That's why it works in Java 🙂 pbandk isn't doing the correct thing for proto2 required fields that contain default values.

@garyp Hi, Do we have a fix ready for pbandk default values in Kotlin?

@garyp garyp added this to the 0.10.0 milestone Sep 15, 2020
@garyp
Copy link
Collaborator

garyp commented Sep 15, 2020

@sujithkris I was able to reproduce the bug with a unit test. Unfortunately it doesn't look like pbandk ever properly supported required proto2 fields (despite the documentation), so this is going to be a bit more involved to fix than I expected. It won't make the 0.9.0 release (which should be this or next week), but we'll try to get it in for the 0.10.0 release.

Also, to clarify, the bug only impacts proto2 required fields that contain default values (as you have in your example up above). proto2 optional fields with default values and proto3 fields with default values should be working correctly.

@garyp garyp changed the title Deserialization Exceptions in apps using java protobuf libs Proto2 required fields that contain default values are not serialized correctly Sep 15, 2020
@garyp garyp modified the milestones: 0.10.0, 0.11.0 Mar 12, 2021
@garyp garyp modified the milestones: 0.11.0, 0.12.0 Sep 24, 2021
@garyp garyp modified the milestones: 0.12.0, 0.13.0 Oct 29, 2021
@garyp garyp modified the milestones: 0.13.0, 0.14.0 Mar 17, 2022
garyp added a commit that referenced this issue Mar 31, 2022
Also refactor some of the `hasPresence`-related code in the code
generator to make it easier to understand.

Fixes #71.
garyp added a commit that referenced this issue Mar 31, 2022
Also refactor some of the `hasPresence`-related code in the code
generator to make it easier to understand.

Fixes #71.
garyp added a commit that referenced this issue May 17, 2022
Also refactor some of the `hasPresence`-related code in the code generator to make it easier to understand.

Fixes #71.

## Guide to changes

There's a lot of noise in this PR from empty lines being added to generated code. The interesting changes are in `File.kt`, `FileBuilder.kt` and `CodeGenerator.kt` under `protoc-gen-pbandk/lib/src/commonMain/kotlin/pbandk/gen/`. You can see an example of how these changes impact the generated code in `runtime/src/commonMain/kotlin/pbandk/wkt/descriptor.kt`, where a couple `required` fields in the `NamePart` message were previously being generated incorrectly and now are handled properly.

Aside from the main changes, there is also some slight refactoring of the `kotlinJavaRoundtripTest()` method used in some of the tests (and the method also got renamed to `pbandkJavaRoundtripTest()`).
garyp added a commit that referenced this issue Mar 7, 2023
Also refactor some of the `hasPresence`-related code in the code generator to make it easier to understand.

Fixes #71.

There's a lot of noise in this PR from empty lines being added to generated code. The interesting changes are in `File.kt`, `FileBuilder.kt` and `CodeGenerator.kt` under `protoc-gen-pbandk/lib/src/commonMain/kotlin/pbandk/gen/`. You can see an example of how these changes impact the generated code in `runtime/src/commonMain/kotlin/pbandk/wkt/descriptor.kt`, where a couple `required` fields in the `NamePart` message were previously being generated incorrectly and now are handled properly.

Aside from the main changes, there is also some slight refactoring of the `kotlinJavaRoundtripTest()` method used in some of the tests (and the method also got renamed to `pbandkJavaRoundtripTest()`).
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug Something isn't working component-codegen question Further information is requested syntax-proto2
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants