[custom serde annotations] the trait `Deserialize<'_>` is not implemented for `MessageField<T>`
svanharmelen opened this issue · comments
I also just opened #702 as well as my goal is to parse both protobuf and JSON payloads using the same generated structs using either protobuf-json-mapping
or custom Serde annotations. The other issue describes an issue with protobuf-json-mapping
and this issue is used to describe an issue with using custom Serde annotations.
To make it easy to reproduce the issue, I created a debug-example repo with a "working" example giving the error: https://github.com/svanharmelen/debug-example/tree/serde (notice this example is in the serde
branch)
I'm using an update proto file:
syntax = "proto2";
message TestMessage {
message SubMessage {
optional string name = 1;
}
message MainMessage {
optional string name = 1;
optional SubMessage submessage = 2;
oneof value {
uint32 int_value = 3;
uint64 long_value = 4;
float float_value = 5;
double double_value = 6;
}
}
}
But this time I am using this lib.rs
:
include!(concat!(env!("OUT_DIR"), "/protos/mod.rs"));
#[cfg(test)]
mod test {
use crate::example::test_message::{main_message::Value, MainMessage};
#[test]
fn test() {
let json = r#"{
"name": "test",
"value": 10.3
}"#;
let message: MainMessage = serde_json::from_str(json).expect("failed to parse JSON");
assert_eq!(message.name, Some("test".to_string()));
assert_eq!(message.value, Some(Value::FloatValue(10.3)));
}
}
The error I get is about MessageField<T>
types not implementing the Deserialize
trait and I have now idea how I should fix that in a generic way (the actual proto file I use has a bunch of these embedded submessages):
3897 | pub properties: ::protobuf::MessageField<PropertySet>,
| ^^^ the trait `Deserialize<'_>` is not implemented for `MessageField<PropertySet>`
I'm fine to use either Serde annotations or protobuf-json-mapping
, whichever one is easier to fix will do I guess 😉
Thanks!
I think some serde annotation can be inserted to specify message field should be parsed/serialized with custom function.
Yes, I was thinking the same... But I cannot find a way to "detect" which field are of type MessageField<T>
in the available CustomizeCallback
methods in order to write an annotation on them. Any suggestions?
@svanharmelen I'm not sure if you ever figured this out, but I have some solution, although I am using it to skip adding derives on MessageField.
The fn message
bit adds the SerDe derive above the outer message type, then I skip on inner MessageField, and special fields. Apparently you can use field.proto().type_()
to check the type of field.
struct GenSerde;
impl CustomizeCallback for GenSerde {
fn message(&self, _message: &MessageDescriptor) -> Customize {
Customize::default().before("#[derive(::serde::Serialize, ::serde::Deserialize)]")
}
// Skips adding the derive macro above field-level Message types, as they
// are wrapped in a MessageField struct which is not Serialize or Deserialize
fn field(&self, field: &FieldDescriptor) -> Customize {
if field.proto().type_() == Type::TYPE_MESSAGE {
Customize::default().before("#[serde(skip)]")
} else {
Customize::default()
}
}
fn special_field(&self, _message: &MessageDescriptor, _field: &str) -> Customize {
Customize::default().before("#[serde(skip)]")
}
}
Thanks for your reply @icdevin, much appreciated!
I ended up making it very specific by using the field name. Feels a bit nasty, but it does solve the issue 😏 If I remember correctly I did try your suggestion, but that ended up skipping more field then needed. Might check it again when I have to update or make changes to the crate again...