SoFunction
Updated on 2025-03-05

Go language uses protojson library to implement Protocol Buffers and JSON conversion

Protojson Introduction

Protojson is Google's JSON encoding library for Protocol Buffers data format. It provides Go language developers with convenient tools and APIs for conversion between Protocol Buffers messages and JSON. Common APIs:

func Format(m ) string
func Marshal(m ) ([]byte, error)
func Unmarshal(b []byte, m ) error
type MarshalOptions
func (o MarshalOptions) Format(m ) string
func (o MarshalOptions) Marshal(m ) ([]byte, error)
func (o MarshalOptions) MarshalAppend(b []byte, m ) ([]byte, error)
type UnmarshalOptions
func (o UnmarshalOptions) Unmarshal(b []byte, m ) error

Next, we demonstrate how to use it through some practical examples.

Install protoc

  • Setting up Go Env(window os)
# go env -w GOPROXY=
# go env -w GOBIN=%USERPROFILE%\go\bin

Where USERPROFILE is the default user installation path, example: C:\Users\jeffff

  • Download and install

Download the protoc version suitable for your os, copy it to the GOBIN directory, and download the link/protocolbuffers/protobuf/releases

  • Check whether the installation is successful
# protoc --version
libprotoc 24.3

Install protoc-gen-go

Here you use go install to install. After the installation is successful, it will be added to the GOBIN directory.

# go install /protobuf/cmd/protoc-gen-go@latest
# protoc-gen-go --version
protoc-gen-go v1.31.0

Example

Create /example/ Create /example/

syntax = "proto3";
package ;
option go_package = "./;pb";
message User {
  string id = 1;
  string name = 3;
  int32  age = 4;
  string real_name = 5;
  string date = 8;
}

Execute the following command to generate /example/file

#protoc --go_out=.  

Create and quickly practice the functions of each API

package main
import (
    "fmt"
    "/google/uuid"
    "/luckytking/practices/libs/protojson/pb"
    "/protobuf/encoding/protojson"
)
func userInfo() * {
    return &{
       Id:       (),
       Name:     (),
       Age:      33,
       RealName: (),
       Date:     "",
       //Date:     ().Format(),
    }
}
func main() {
    info := userInfo()
    (":", info)
    format := (info)
    (":", format)
    marshal, err := (info)
    if err != nil {
       panic(err)
    }
    (":", string(marshal))
    user1 := &{}
    err = (marshal, user1)
    (":", user1)
    //marshalOpt :=
    marshal2, err := {
       EmitUnpopulated: true,
    }.Marshal(info)
    if err != nil {
       panic(err)
    }
    ("data.Marshal2:", string(marshal2))
    user2 := &{}
    err = (marshal2, user2)
    ("data.Unmarshal2:", user2)
} 

The output is as follows:

: id:"df8bbcca-d8b9-4e41-91ff-6ccf01567d27"  name:"67115015-48bb-4284-b601-e9348a53d40f"  age:33  real_name:"bed916f1-0fb3-413c-9de3-222cbc90c814"
: {
  "id":  "df8bbcca-d8b9-4e41-91ff-6ccf01567d27",
  "name":  "67115015-48bb-4284-b601-e9348a53d40f",
  "age":  33,
  "realName":  "bed916f1-0fb3-413c-9de3-222cbc90c814"
}
: {"id":"df8bbcca-d8b9-4e41-91ff-6ccf01567d27", "name":"67115015-48bb-4284-b601-e9348a53d40f", "age":33, "realName":"bed916f1-0fb3-413c-9de3-222cbc90c814"}
: id:"df8bbcca-d8b9-4e41-91ff-6ccf01567d27"  name:"67115015-48bb-4284-b601-e9348a53d40f"  age:33  real_name:"bed916f1-0fb3-413c-9de3-222cbc90c814"
data.Marshal2: {"id":"df8bbcca-d8b9-4e41-91ff-6ccf01567d27", "name":"67115015-48bb-4284-b601-e9348a53d40f", "age":33, "realName":"bed916f1-0fb3-413c-9de3-222cbc90c814", "date":""}
data.Unmarshal2: id:"df8bbcca-d8b9-4e41-91ff-6ccf01567d27"  name:"67115015-48bb-4284-b601-e9348a53d40f"  age:33  real_name:"bed916f1-0fb3-413c-9de3-222cbc90c814"

In the above example:

  • Convert protobuf to JSON format via Marshal or function.
  • Convert JSON format data into protobuf messages through Unmarshal or function.
  • MarshalOptions provides some customization options, such as whether "EmitUnpopulated: true," in the example outputs unset fields. Although ="" (default value), null characters are still output.

More options references

type MarshalOptions struct {
	
        // Multiline Specifies whether the marshaling disassembler should format the output in indentation and place each text element on a new line.  // If Indent is an empty string, select any indent.	Multiline bool
        // Indent specifies the indented character set used in multi-line formatted output.	So that each current page has indentation,and
	// End with a newline character.  If non-empty, Multiline is considered true.	// Indentation can only be composed of spaces or tabs.	Indent string
        // AllowPartial allows marshaling messages that are missing required fields	// without returning an error.  If AllowPartial is false (default),	// If any required fields are missing, Marshal will return an error.	AllowPartial bool
	// UseProtoNames Use the proto field name instead of the camel name in the JSON field name.	UseProtoNames bool
        // UseEnumNumbers emits the enum value as a number.	UseEnumNumbers bool
        // EmitUnpopulated Specifies whether to issue unfilled fields.  //It won't	Issue unfilled oneof Field or unpopulated extended field。
	// The JSON value emitted by the unfilled field is as follows:	//  ╔═══════╤════════════════════════════╗
	//  ║ JSON  │ Protobuf field             ║
	//  ╠═══════╪════════════════════════════╣
	//  ║ false │ proto3 boolean fields      ║
	//  ║ 0     │ proto3 numeric fields      ║
	//  ║ ""    │ proto3 string/bytes fields ║
	//  ║ null  │ proto2 scalar fields       ║
	//  ║ null  │ message fields             ║
	//  ║ []    │ list fields                ║
	//  ║ {}    │ map fields                 ║
	//  ╚═══════╧════════════════════════════╝
	EmitUnpopulated bool
	// parser is used in extension	// Find type when message.  If zero, it is used by default.	Resolver interface {
		
		
	}
}

Performance comparison protojson VS encoding/json

Create example_test.go

package main
import (
    "encoding/json"
    "/protobuf/encoding/protojson"
    "testing"
)
func BenchmarkProtoJson(b *) {
    gen := userInfo()
    for i := 0; i < ; i++ {
       (gen)
    }
}
func BenchmarkStdJson(b *) {
    gen := userInfo()
    for i := 0; i < ; i++ {
       (gen)
    }
} 

The conclusion is as follows:

BenchmarkProtoJson
BenchmarkProtoJson-4      230895              4556 ns/op
BenchmarkStdJson
BenchmarkStdJson-4        715443              1732 ns/op

Summarize

This article introduces the conversion between Protojson library and JSON through practical examples, as well as the performance comparison between it and the standard library encoding/json. In general, Google Protocol Buffers customizes API protocols and uses Protojson to solve the transfer format conversion. In distributed systems, whether it is Rpc or Http network communication, I believe Protojson can perform well.

The above is the detailed content of Go using the protojson library to implement Protocol Buffers and JSON conversion. For more information about Go Protocol Buffers and JSON conversion, please follow my other related articles!