Skip to content

Commit

Permalink
Fix json serialization of wrapper types
Browse files Browse the repository at this point in the history
  • Loading branch information
andersfugmann committed Mar 9, 2024
1 parent 0518367 commit d46be89
Show file tree
Hide file tree
Showing 3 changed files with 160 additions and 11 deletions.
25 changes: 15 additions & 10 deletions src/ocaml_protoc_plugin/serialize_json.ml
Original file line number Diff line number Diff line change
Expand Up @@ -140,16 +140,16 @@ let%expect_test "timestamp_to_json" =
let wrapper_to_json json = get_key ~f:(fun id -> id) ~default:`Null "value" json

(* Convert already emitted json based on json mappings *)
let map_json: type a. (module Message with type t = a) -> Yojson.Basic.t -> Yojson.Basic.t = fun (module Message) ->
let map_json: type a. (module Message with type t = a) -> (Yojson.Basic.t -> Yojson.Basic.t) option = fun (module Message) ->
match Message.name' () |> String.split_on_char ~sep:'.' with
| [_; "google"; "protobuf"; "Empty"] ->
fun json -> json
Some (fun json -> json)
(* Duration - google/protobuf/timestamp.proto *)
| [_; "google"; "protobuf"; "Duration"] ->
duration_to_json
Some (duration_to_json)
(* Timestamp - google/protobuf/timestamp.proto *)
| [_; "google"; "protobuf"; "Timestamp"] ->
timestamp_to_json
Some (timestamp_to_json)
(* Wrapper types - google/protobuf/wrappers.proto *)
| [_; "google"; "protobuf"; "DoubleValue"]
| [_; "google"; "protobuf"; "FloatValue"]
Expand All @@ -160,17 +160,17 @@ let map_json: type a. (module Message with type t = a) -> Yojson.Basic.t -> Yojs
| [_; "google"; "protobuf"; "BoolValue"]
| [_; "google"; "protobuf"; "StringValue"]
| [_; "google"; "protobuf"; "BytesValue"] ->
wrapper_to_json
Some (wrapper_to_json)
| [_; "google"; "protobuf"; "Value"] ->
let map = function
| `Assoc [_, json] -> json
| json -> value_error "google.protobuf.Value" json
in
map
Some map
(* FieldMask - /usr/include/google/protobuf/field_mask.proto *)
| [_; "google"; "protobuf"; "FieldMask"] ->
let open StdLabels in
let convert = function
let map = function
| `Assoc ["masks", `List masks] ->
List.map ~f:(function
| `String mask -> (to_camel_case mask)
Expand All @@ -180,8 +180,8 @@ let map_json: type a. (module Message with type t = a) -> Yojson.Basic.t -> Yojs
|> fun mask -> `String mask
| json -> value_error "google.protobuf.FieldMask" json
in
convert
| _ -> fun json -> json
Some map
| _ -> None

let rec json_of_spec: type a b. enum_names:bool -> json_names:bool -> omit_default_values:bool -> (a, b) spec -> a -> Yojson.Basic.t =
fun ~enum_names ~json_names ~omit_default_values -> function
Expand Down Expand Up @@ -221,7 +221,12 @@ let rec json_of_spec: type a b. enum_names:bool -> json_names:bool -> omit_defau
| false -> enum_value ~f:Enum.to_int
end
| Message (module Message) ->
fun v -> Message.to_json ~enum_names ~json_names ~omit_default_values v |> map_json (module Message)
let omit_default_values, map =
match map_json (module Message) with
| Some map -> false, map
| None -> omit_default_values, (fun json -> json)
in
fun v -> Message.to_json ~enum_names ~json_names ~omit_default_values v |> map

and write: type a b. enum_names:bool -> json_names:bool -> omit_default_values:bool -> (a, b) compound -> a -> field list =
fun ~enum_names ~json_names ~omit_default_values -> function
Expand Down
30 changes: 30 additions & 0 deletions test/json_encoding.proto
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,41 @@ syntax = "proto3";

import "google/protobuf/duration.proto";
import "google/protobuf/timestamp.proto";
import "google/protobuf/empty.proto";
import "google/protobuf/struct.proto";
import "google/protobuf/any.proto";
import "google/protobuf/wrappers.proto";

package Json_test;
message Duration {
google.protobuf.Duration duration = 1;
}

message Timestamp {
google.protobuf.Timestamp timestamp = 1;
}

message Empty {
google.protobuf.Empty empty = 1;
}

message Value {
google.protobuf.Struct struct = 1;
}

message Any {
google.protobuf.Any any = 1;
}

// Wrappers
message Wrappers {
google.protobuf.DoubleValue double = 1;
google.protobuf.FloatValue float = 2;
google.protobuf.Int64Value s64 = 3;
google.protobuf.UInt64Value u64 = 4;
google.protobuf.Int32Value s32 = 5;
google.protobuf.UInt32Value u32 = 6;
google.protobuf.BoolValue bool = 7;
google.protobuf.StringValue string = 8;
google.protobuf.BytesValue bytes = 9;
}
116 changes: 115 additions & 1 deletion test/json_encoding_test.ml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
open Json_encoding
open Json_encoding.Json_test
module G = Google_types_pp

let%expect_test _ =
Expand Down Expand Up @@ -60,3 +60,117 @@ let%expect_test _ =
}
Json: { "timestamp": "1970-01-01T00:00:00.000000005Z" }
Ref: { "timestamp": "1970-01-01T00:00:00.000000005Z" } |}]

let%expect_test _ =
let module T = Empty in
let module I = G.Empty.Google.Protobuf.Empty in
Some (I.make ()) |> Test_lib.test_encode ~debug_json:true (module T);
();
[%expect {|
empty {
}
Json: { "empty": {} }
Ref: { "empty": {} } |}]


let%expect_test _ =
let module T = Wrappers in
T.make () |> Test_lib.test_encode ~debug_json:true (module T);
let bytes = Bytes.of_string "bytes" in
T.make ~double:0.0 ~float:0.0 ~s64:0 ~u64:0 ~s32:0 ~u32:0 ~string:"" ~bytes:Bytes.empty ~bool:false ()
|> Test_lib.test_encode ~debug_json:true (module T);
T.make ~double:5.5 ~float:5.5 ~s64:5 ~u64:5 ~s32:5 ~u32:5 ~string:"str" ~bytes ~bool:true ()
|> Test_lib.test_encode ~debug_json:true (module T);
();
[%expect {|
Json: {}
Ref: {}
double {
}
float {
}
s64 {
}
u64 {
}
s32 {
}
u32 {
}
bool {
}
string {
}
bytes {
}
Json: {
"double": 0,
"float": 0,
"s64": "0",
"u64": "0",
"s32": 0,
"u32": 0,
"bool": false,
"string": "",
"bytes": ""
}
Ref: {
"double": 0,
"float": 0,
"s64": "0",
"u64": "0",
"s32": 0,
"u32": 0,
"bool": false,
"string": "",
"bytes": ""
}
double {
value: 5.5
}
float {
value: 5.5
}
s64 {
value: 5
}
u64 {
value: 5
}
s32 {
value: 5
}
u32 {
value: 5
}
bool {
value: true
}
string {
value: "str"
}
bytes {
value: "bytes"
}
Json: {
"double": 5.5,
"float": 5.5,
"s64": "5",
"u64": "5",
"s32": 5,
"u32": 5,
"bool": true,
"string": "str",
"bytes": "Ynl0ZXM="
}
Ref: {
"double": 5.5,
"float": 5.5,
"s64": "5",
"u64": "5",
"s32": 5,
"u32": 5,
"bool": true,
"string": "str",
"bytes": "Ynl0ZXM="
} |}]

0 comments on commit d46be89

Please sign in to comment.