From 86e5794cd12dd538450b4459b36d3ea05a7d16d6 Mon Sep 17 00:00:00 2001 From: lou Date: Mon, 20 Jan 2025 18:00:41 +0800 Subject: [PATCH 1/2] support json format in query string Signed-off-by: lou --- encoding/form/proto_decode.go | 28 +- encoding/form/proto_decode_test.go | 55 ++++ internal/testdata/complex/complex.pb.go | 417 +++++++++++++++++++----- internal/testdata/complex/complex.proto | 19 +- 4 files changed, 429 insertions(+), 90 deletions(-) diff --git a/encoding/form/proto_decode.go b/encoding/form/proto_decode.go index e327b5e004e..cb9c1ecb417 100644 --- a/encoding/form/proto_decode.go +++ b/encoding/form/proto_decode.go @@ -13,6 +13,7 @@ import ( "google.golang.org/protobuf/proto" "google.golang.org/protobuf/reflect/protoreflect" "google.golang.org/protobuf/reflect/protoregistry" + "google.golang.org/protobuf/types/dynamicpb" "google.golang.org/protobuf/types/known/durationpb" "google.golang.org/protobuf/types/known/fieldmaskpb" "google.golang.org/protobuf/types/known/structpb" @@ -26,11 +27,24 @@ var errInvalidFormatMapKey = errors.New("invalid formatting for map key") // DecodeValues decode url value into proto message. func DecodeValues(msg proto.Message, values url.Values) error { - for key, values := range values { - if err := populateFieldValues(msg.ProtoReflect(), strings.Split(key, "."), values); err != nil { + dynamicMessage := dynamicpb.NewMessage(msg.ProtoReflect().Descriptor()) + + for key, vals := range values { + if err := populateFieldValues(dynamicMessage, strings.Split(key, "."), vals); err != nil { return err } } + + data, err := proto.Marshal(dynamicMessage) + if err != nil { + return fmt.Errorf("failed to marshal dynamic message: %v", err) + } + + err = proto.Unmarshal(data, msg) + if err != nil { + return fmt.Errorf("failed to unmarshal: %v", err) + } + return nil } @@ -325,8 +339,16 @@ func parseMessage(md protoreflect.MessageDescriptor, value string) (protoreflect } msg = &v default: - return protoreflect.Value{}, fmt.Errorf("unsupported message type: %q", string(md.FullName())) + msg = dynamicpb.NewMessage(md) + if err := protojson.Unmarshal([]byte(value), msg); err != nil { + return protoreflect.Value{}, err + } } + + if msg == nil { + return protoreflect.Value{}, nil + } + return protoreflect.ValueOfMessage(msg.ProtoReflect()), nil } diff --git a/encoding/form/proto_decode_test.go b/encoding/form/proto_decode_test.go index a82b5576047..c2c5622dc09 100644 --- a/encoding/form/proto_decode_test.go +++ b/encoding/form/proto_decode_test.go @@ -7,6 +7,7 @@ import ( "strconv" "testing" + "google.golang.org/protobuf/encoding/protojson" "google.golang.org/protobuf/reflect/protoreflect" "github.com/go-kratos/kratos/v2/internal/testdata/complex" @@ -48,6 +49,60 @@ func TestDecodeValues(t *testing.T) { } } +func TestDecodeJsonValues(t *testing.T) { + origin := &complex.ComplexField{ + Name: "ComplexField", + Inner1: &complex.Inner1{ + Name: "Inner1", + Sex: complex.Sex_man, + }, + Inner2: []*complex.Inner2{ + { + Name: "Inner11", + Inner1: []*complex.Inner1{ + { + Name: "Inner111", + Sex: complex.Sex_man, + }, + }, + }, + { + Name: "Inner12", + Inner1: []*complex.Inner1{ + { + Name: "Inner121", + Sex: complex.Sex_man, + }, + { + Name: "Inner122", + Sex: complex.Sex_woman, + }, + }, + }, + }, + } + data, err := protojson.Marshal(origin) + if err != nil { + t.Fatal(err) + } + fmt.Println(string(data)) + + // url.ParseQuery("complex_field={"name":"ComplexField", "inner1":{"name":"Inner1"}, "inner2":[{"name":"Inner11", "inner1":[{"name":"Inner111"}]}, {"name":"Inner12", "inner1":[{"name":"Inner121"}, {"name":"Inner122", "sex":"woman"}]}]}") + form, err := url.ParseQuery(fmt.Sprintf("complex_field=%s", string(data))) + if err != nil { + t.Fatal(err) + } + + comp := &complex.Complex{} + err = DecodeValues(comp, form) + if err != nil { + t.Fatal(err) + } + if reflect.DeepEqual(origin, comp.ComplexField) { + t.Errorf("want %v, got %v", origin, comp.ComplexField) + } +} + func TestGetFieldDescriptor(t *testing.T) { comp := &complex.Complex{} diff --git a/internal/testdata/complex/complex.pb.go b/internal/testdata/complex/complex.pb.go index 216c36177b4..17d9396e9ae 100644 --- a/internal/testdata/complex/complex.pb.go +++ b/internal/testdata/complex/complex.pb.go @@ -1,7 +1,7 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.27.1 -// protoc v3.19.1 +// protoc-gen-go v1.34.2 +// protoc v4.25.3 // source: complex.proto package complex @@ -77,32 +77,33 @@ type Complex struct { unknownFields protoimpl.UnknownFields // Id represents the message identifier. - Id int64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` - NoOne string `protobuf:"bytes,2,opt,name=no_one,json=numberOne,proto3" json:"no_one,omitempty"` - Simple *Simple `protobuf:"bytes,3,opt,name=simple,json=very_simple,proto3" json:"simple,omitempty"` - Simples []string `protobuf:"bytes,4,rep,name=simples,proto3" json:"simples,omitempty"` - B bool `protobuf:"varint,5,opt,name=b,proto3" json:"b,omitempty"` - Sex Sex `protobuf:"varint,6,opt,name=sex,proto3,enum=testproto.Sex" json:"sex,omitempty"` - Age int32 `protobuf:"varint,7,opt,name=age,proto3" json:"age,omitempty"` - A uint32 `protobuf:"varint,8,opt,name=a,proto3" json:"a,omitempty"` - Count uint64 `protobuf:"varint,9,opt,name=count,proto3" json:"count,omitempty"` - Price float32 `protobuf:"fixed32,10,opt,name=price,proto3" json:"price,omitempty"` - D float64 `protobuf:"fixed64,11,opt,name=d,proto3" json:"d,omitempty"` - Byte []byte `protobuf:"bytes,12,opt,name=byte,proto3" json:"byte,omitempty"` - Timestamp *timestamppb.Timestamp `protobuf:"bytes,13,opt,name=timestamp,proto3" json:"timestamp,omitempty"` - Duration *durationpb.Duration `protobuf:"bytes,14,opt,name=duration,proto3" json:"duration,omitempty"` - Field *fieldmaskpb.FieldMask `protobuf:"bytes,15,opt,name=field,proto3" json:"field,omitempty"` - Double *wrapperspb.DoubleValue `protobuf:"bytes,16,opt,name=double,proto3" json:"double,omitempty"` - Float *wrapperspb.FloatValue `protobuf:"bytes,17,opt,name=float,proto3" json:"float,omitempty"` - Int64 *wrapperspb.Int64Value `protobuf:"bytes,18,opt,name=int64,proto3" json:"int64,omitempty"` - Int32 *wrapperspb.Int32Value `protobuf:"bytes,19,opt,name=int32,proto3" json:"int32,omitempty"` - Uint64 *wrapperspb.UInt64Value `protobuf:"bytes,20,opt,name=uint64,proto3" json:"uint64,omitempty"` - Uint32 *wrapperspb.UInt32Value `protobuf:"bytes,21,opt,name=uint32,proto3" json:"uint32,omitempty"` - Bool *wrapperspb.BoolValue `protobuf:"bytes,22,opt,name=bool,proto3" json:"bool,omitempty"` - String_ *wrapperspb.StringValue `protobuf:"bytes,23,opt,name=string,proto3" json:"string,omitempty"` - Bytes *wrapperspb.BytesValue `protobuf:"bytes,24,opt,name=bytes,proto3" json:"bytes,omitempty"` - Map map[string]string `protobuf:"bytes,25,rep,name=map,proto3" json:"map,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` - MapInt64Key map[int64]string `protobuf:"bytes,26,rep,name=map_int64_key,proto3" json:"map_int64_key,omitempty" protobuf_key:"varint,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + Id int64 `protobuf:"varint,1,opt,name=id,proto3" json:"id,omitempty"` + NoOne string `protobuf:"bytes,2,opt,name=no_one,json=numberOne,proto3" json:"no_one,omitempty"` + Simple *Simple `protobuf:"bytes,3,opt,name=simple,json=very_simple,proto3" json:"simple,omitempty"` + Simples []string `protobuf:"bytes,4,rep,name=simples,proto3" json:"simples,omitempty"` + B bool `protobuf:"varint,5,opt,name=b,proto3" json:"b,omitempty"` + Sex Sex `protobuf:"varint,6,opt,name=sex,proto3,enum=testproto.Sex" json:"sex,omitempty"` + Age int32 `protobuf:"varint,7,opt,name=age,proto3" json:"age,omitempty"` + A uint32 `protobuf:"varint,8,opt,name=a,proto3" json:"a,omitempty"` + Count uint64 `protobuf:"varint,9,opt,name=count,proto3" json:"count,omitempty"` + Price float32 `protobuf:"fixed32,10,opt,name=price,proto3" json:"price,omitempty"` + D float64 `protobuf:"fixed64,11,opt,name=d,proto3" json:"d,omitempty"` + Byte []byte `protobuf:"bytes,12,opt,name=byte,proto3" json:"byte,omitempty"` + Timestamp *timestamppb.Timestamp `protobuf:"bytes,13,opt,name=timestamp,proto3" json:"timestamp,omitempty"` + Duration *durationpb.Duration `protobuf:"bytes,14,opt,name=duration,proto3" json:"duration,omitempty"` + Field *fieldmaskpb.FieldMask `protobuf:"bytes,15,opt,name=field,proto3" json:"field,omitempty"` + Double *wrapperspb.DoubleValue `protobuf:"bytes,16,opt,name=double,proto3" json:"double,omitempty"` + Float *wrapperspb.FloatValue `protobuf:"bytes,17,opt,name=float,proto3" json:"float,omitempty"` + Int64 *wrapperspb.Int64Value `protobuf:"bytes,18,opt,name=int64,proto3" json:"int64,omitempty"` + Int32 *wrapperspb.Int32Value `protobuf:"bytes,19,opt,name=int32,proto3" json:"int32,omitempty"` + Uint64 *wrapperspb.UInt64Value `protobuf:"bytes,20,opt,name=uint64,proto3" json:"uint64,omitempty"` + Uint32 *wrapperspb.UInt32Value `protobuf:"bytes,21,opt,name=uint32,proto3" json:"uint32,omitempty"` + Bool *wrapperspb.BoolValue `protobuf:"bytes,22,opt,name=bool,proto3" json:"bool,omitempty"` + String_ *wrapperspb.StringValue `protobuf:"bytes,23,opt,name=string,proto3" json:"string,omitempty"` + Bytes *wrapperspb.BytesValue `protobuf:"bytes,24,opt,name=bytes,proto3" json:"bytes,omitempty"` + Map map[string]string `protobuf:"bytes,25,rep,name=map,proto3" json:"map,omitempty" protobuf_key:"bytes,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + MapInt64Key map[int64]string `protobuf:"bytes,26,rep,name=map_int64_key,proto3" json:"map_int64_key,omitempty" protobuf_key:"varint,1,opt,name=key,proto3" protobuf_val:"bytes,2,opt,name=value,proto3"` + ComplexField *ComplexField `protobuf:"bytes,27,opt,name=complex_field,json=complexField,proto3" json:"complex_field,omitempty"` } func (x *Complex) Reset() { @@ -319,6 +320,13 @@ func (x *Complex) GetMapInt64Key() map[int64]string { return nil } +func (x *Complex) GetComplexField() *ComplexField { + if x != nil { + return x.ComplexField + } + return nil +} + type Simple struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -366,6 +374,179 @@ func (x *Simple) GetComponent() string { return "" } +type ComplexField struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + Inner1 *Inner1 `protobuf:"bytes,2,opt,name=inner1,proto3" json:"inner1,omitempty"` + Inner2 []*Inner2 `protobuf:"bytes,3,rep,name=inner2,proto3" json:"inner2,omitempty"` +} + +func (x *ComplexField) Reset() { + *x = ComplexField{} + if protoimpl.UnsafeEnabled { + mi := &file_complex_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ComplexField) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ComplexField) ProtoMessage() {} + +func (x *ComplexField) ProtoReflect() protoreflect.Message { + mi := &file_complex_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ComplexField.ProtoReflect.Descriptor instead. +func (*ComplexField) Descriptor() ([]byte, []int) { + return file_complex_proto_rawDescGZIP(), []int{2} +} + +func (x *ComplexField) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *ComplexField) GetInner1() *Inner1 { + if x != nil { + return x.Inner1 + } + return nil +} + +func (x *ComplexField) GetInner2() []*Inner2 { + if x != nil { + return x.Inner2 + } + return nil +} + +type Inner1 struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + Sex Sex `protobuf:"varint,2,opt,name=sex,proto3,enum=testproto.Sex" json:"sex,omitempty"` +} + +func (x *Inner1) Reset() { + *x = Inner1{} + if protoimpl.UnsafeEnabled { + mi := &file_complex_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Inner1) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Inner1) ProtoMessage() {} + +func (x *Inner1) ProtoReflect() protoreflect.Message { + mi := &file_complex_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Inner1.ProtoReflect.Descriptor instead. +func (*Inner1) Descriptor() ([]byte, []int) { + return file_complex_proto_rawDescGZIP(), []int{3} +} + +func (x *Inner1) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *Inner1) GetSex() Sex { + if x != nil { + return x.Sex + } + return Sex_man +} + +type Inner2 struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Name string `protobuf:"bytes,1,opt,name=name,proto3" json:"name,omitempty"` + Inner1 []*Inner1 `protobuf:"bytes,2,rep,name=inner1,proto3" json:"inner1,omitempty"` +} + +func (x *Inner2) Reset() { + *x = Inner2{} + if protoimpl.UnsafeEnabled { + mi := &file_complex_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Inner2) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Inner2) ProtoMessage() {} + +func (x *Inner2) ProtoReflect() protoreflect.Message { + mi := &file_complex_proto_msgTypes[4] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Inner2.ProtoReflect.Descriptor instead. +func (*Inner2) Descriptor() ([]byte, []int) { + return file_complex_proto_rawDescGZIP(), []int{4} +} + +func (x *Inner2) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *Inner2) GetInner1() []*Inner1 { + if x != nil { + return x.Inner1 + } + return nil +} + var File_complex_proto protoreflect.FileDescriptor var file_complex_proto_rawDesc = []byte{ @@ -378,7 +559,7 @@ var file_complex_proto_rawDesc = []byte{ 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x5f, 0x6d, 0x61, 0x73, 0x6b, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x1a, 0x1e, 0x67, 0x6f, 0x6f, 0x67, 0x6c, 0x65, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x62, 0x75, 0x66, 0x2f, 0x77, - 0x72, 0x61, 0x70, 0x70, 0x65, 0x72, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0x85, 0x09, + 0x72, 0x61, 0x70, 0x70, 0x65, 0x72, 0x73, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x22, 0xc3, 0x09, 0x0a, 0x07, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x78, 0x12, 0x0e, 0x0a, 0x02, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x02, 0x69, 0x64, 0x12, 0x19, 0x0a, 0x06, 0x6e, 0x6f, 0x5f, 0x6f, 0x6e, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x09, 0x6e, 0x75, 0x6d, 0x62, 0x65, @@ -443,25 +624,45 @@ var file_complex_proto_rawDesc = []byte{ 0x6b, 0x65, 0x79, 0x18, 0x1a, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x23, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x78, 0x2e, 0x4d, 0x61, 0x70, 0x49, 0x6e, 0x74, 0x36, 0x34, 0x4b, 0x65, 0x79, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x52, 0x0d, - 0x6d, 0x61, 0x70, 0x5f, 0x69, 0x6e, 0x74, 0x36, 0x34, 0x5f, 0x6b, 0x65, 0x79, 0x1a, 0x36, 0x0a, - 0x08, 0x4d, 0x61, 0x70, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, - 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, - 0x65, 0x3a, 0x02, 0x38, 0x01, 0x1a, 0x3e, 0x0a, 0x10, 0x4d, 0x61, 0x70, 0x49, 0x6e, 0x74, 0x36, - 0x34, 0x4b, 0x65, 0x79, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, - 0x18, 0x01, 0x20, 0x01, 0x28, 0x03, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, - 0x61, 0x6c, 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, - 0x65, 0x3a, 0x02, 0x38, 0x01, 0x22, 0x26, 0x0a, 0x06, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x12, - 0x1c, 0x0a, 0x09, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x09, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x2a, 0x19, 0x0a, - 0x03, 0x73, 0x65, 0x78, 0x12, 0x07, 0x0a, 0x03, 0x6d, 0x61, 0x6e, 0x10, 0x00, 0x12, 0x09, 0x0a, - 0x05, 0x77, 0x6f, 0x6d, 0x61, 0x6e, 0x10, 0x01, 0x42, 0x57, 0x5a, 0x55, 0x67, 0x69, 0x74, 0x68, - 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x2d, 0x6b, 0x72, 0x61, 0x74, 0x6f, 0x73, - 0x2f, 0x6b, 0x72, 0x61, 0x74, 0x6f, 0x73, 0x2f, 0x63, 0x6d, 0x64, 0x2f, 0x70, 0x72, 0x6f, 0x74, - 0x6f, 0x63, 0x2d, 0x67, 0x65, 0x6e, 0x2d, 0x67, 0x6f, 0x2d, 0x68, 0x74, 0x74, 0x70, 0x2f, 0x69, - 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, 0x67, - 0x2f, 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x78, 0x2f, 0x3b, 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65, - 0x78, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x6d, 0x61, 0x70, 0x5f, 0x69, 0x6e, 0x74, 0x36, 0x34, 0x5f, 0x6b, 0x65, 0x79, 0x12, 0x3c, 0x0a, + 0x0d, 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x78, 0x5f, 0x66, 0x69, 0x65, 0x6c, 0x64, 0x18, 0x1b, + 0x20, 0x01, 0x28, 0x0b, 0x32, 0x17, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x2e, 0x43, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x78, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x52, 0x0c, 0x63, + 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x78, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x1a, 0x36, 0x0a, 0x08, 0x4d, + 0x61, 0x70, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, + 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, + 0x02, 0x38, 0x01, 0x1a, 0x3e, 0x0a, 0x10, 0x4d, 0x61, 0x70, 0x49, 0x6e, 0x74, 0x36, 0x34, 0x4b, + 0x65, 0x79, 0x45, 0x6e, 0x74, 0x72, 0x79, 0x12, 0x10, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, + 0x20, 0x01, 0x28, 0x03, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, 0x6c, + 0x75, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x3a, + 0x02, 0x38, 0x01, 0x22, 0x26, 0x0a, 0x06, 0x53, 0x69, 0x6d, 0x70, 0x6c, 0x65, 0x12, 0x1c, 0x0a, + 0x09, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x09, 0x63, 0x6f, 0x6d, 0x70, 0x6f, 0x6e, 0x65, 0x6e, 0x74, 0x22, 0x78, 0x0a, 0x0c, 0x43, + 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x78, 0x46, 0x69, 0x65, 0x6c, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, + 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, + 0x29, 0x0a, 0x06, 0x69, 0x6e, 0x6e, 0x65, 0x72, 0x31, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x11, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x49, 0x6e, 0x6e, 0x65, + 0x72, 0x31, 0x52, 0x06, 0x69, 0x6e, 0x6e, 0x65, 0x72, 0x31, 0x12, 0x29, 0x0a, 0x06, 0x69, 0x6e, + 0x6e, 0x65, 0x72, 0x32, 0x18, 0x03, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x74, 0x65, 0x73, + 0x74, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x49, 0x6e, 0x6e, 0x65, 0x72, 0x32, 0x52, 0x06, 0x69, + 0x6e, 0x6e, 0x65, 0x72, 0x32, 0x22, 0x3e, 0x0a, 0x06, 0x49, 0x6e, 0x6e, 0x65, 0x72, 0x31, 0x12, + 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, + 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x03, 0x73, 0x65, 0x78, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, + 0x32, 0x0e, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, 0x73, 0x65, 0x78, + 0x52, 0x03, 0x73, 0x65, 0x78, 0x22, 0x47, 0x0a, 0x06, 0x49, 0x6e, 0x6e, 0x65, 0x72, 0x32, 0x12, + 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, + 0x61, 0x6d, 0x65, 0x12, 0x29, 0x0a, 0x06, 0x69, 0x6e, 0x6e, 0x65, 0x72, 0x31, 0x18, 0x02, 0x20, + 0x03, 0x28, 0x0b, 0x32, 0x11, 0x2e, 0x74, 0x65, 0x73, 0x74, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2e, + 0x49, 0x6e, 0x6e, 0x65, 0x72, 0x31, 0x52, 0x06, 0x69, 0x6e, 0x6e, 0x65, 0x72, 0x31, 0x2a, 0x19, + 0x0a, 0x03, 0x73, 0x65, 0x78, 0x12, 0x07, 0x0a, 0x03, 0x6d, 0x61, 0x6e, 0x10, 0x00, 0x12, 0x09, + 0x0a, 0x05, 0x77, 0x6f, 0x6d, 0x61, 0x6e, 0x10, 0x01, 0x42, 0x57, 0x5a, 0x55, 0x67, 0x69, 0x74, + 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x67, 0x6f, 0x2d, 0x6b, 0x72, 0x61, 0x74, 0x6f, + 0x73, 0x2f, 0x6b, 0x72, 0x61, 0x74, 0x6f, 0x73, 0x2f, 0x63, 0x6d, 0x64, 0x2f, 0x70, 0x72, 0x6f, + 0x74, 0x6f, 0x63, 0x2d, 0x67, 0x65, 0x6e, 0x2d, 0x67, 0x6f, 0x2d, 0x68, 0x74, 0x74, 0x70, 0x2f, + 0x69, 0x6e, 0x74, 0x65, 0x72, 0x6e, 0x61, 0x6c, 0x2f, 0x65, 0x6e, 0x63, 0x6f, 0x64, 0x69, 0x6e, + 0x67, 0x2f, 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x78, 0x2f, 0x3b, 0x63, 0x6f, 0x6d, 0x70, 0x6c, + 0x65, 0x78, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( @@ -477,48 +678,56 @@ func file_complex_proto_rawDescGZIP() []byte { } var file_complex_proto_enumTypes = make([]protoimpl.EnumInfo, 1) -var file_complex_proto_msgTypes = make([]protoimpl.MessageInfo, 4) -var file_complex_proto_goTypes = []interface{}{ +var file_complex_proto_msgTypes = make([]protoimpl.MessageInfo, 7) +var file_complex_proto_goTypes = []any{ (Sex)(0), // 0: testproto.sex (*Complex)(nil), // 1: testproto.Complex (*Simple)(nil), // 2: testproto.Simple - nil, // 3: testproto.Complex.MapEntry - nil, // 4: testproto.Complex.MapInt64KeyEntry - (*timestamppb.Timestamp)(nil), // 5: google.protobuf.Timestamp - (*durationpb.Duration)(nil), // 6: google.protobuf.Duration - (*fieldmaskpb.FieldMask)(nil), // 7: google.protobuf.FieldMask - (*wrapperspb.DoubleValue)(nil), // 8: google.protobuf.DoubleValue - (*wrapperspb.FloatValue)(nil), // 9: google.protobuf.FloatValue - (*wrapperspb.Int64Value)(nil), // 10: google.protobuf.Int64Value - (*wrapperspb.Int32Value)(nil), // 11: google.protobuf.Int32Value - (*wrapperspb.UInt64Value)(nil), // 12: google.protobuf.UInt64Value - (*wrapperspb.UInt32Value)(nil), // 13: google.protobuf.UInt32Value - (*wrapperspb.BoolValue)(nil), // 14: google.protobuf.BoolValue - (*wrapperspb.StringValue)(nil), // 15: google.protobuf.StringValue - (*wrapperspb.BytesValue)(nil), // 16: google.protobuf.BytesValue + (*ComplexField)(nil), // 3: testproto.ComplexField + (*Inner1)(nil), // 4: testproto.Inner1 + (*Inner2)(nil), // 5: testproto.Inner2 + nil, // 6: testproto.Complex.MapEntry + nil, // 7: testproto.Complex.MapInt64KeyEntry + (*timestamppb.Timestamp)(nil), // 8: google.protobuf.Timestamp + (*durationpb.Duration)(nil), // 9: google.protobuf.Duration + (*fieldmaskpb.FieldMask)(nil), // 10: google.protobuf.FieldMask + (*wrapperspb.DoubleValue)(nil), // 11: google.protobuf.DoubleValue + (*wrapperspb.FloatValue)(nil), // 12: google.protobuf.FloatValue + (*wrapperspb.Int64Value)(nil), // 13: google.protobuf.Int64Value + (*wrapperspb.Int32Value)(nil), // 14: google.protobuf.Int32Value + (*wrapperspb.UInt64Value)(nil), // 15: google.protobuf.UInt64Value + (*wrapperspb.UInt32Value)(nil), // 16: google.protobuf.UInt32Value + (*wrapperspb.BoolValue)(nil), // 17: google.protobuf.BoolValue + (*wrapperspb.StringValue)(nil), // 18: google.protobuf.StringValue + (*wrapperspb.BytesValue)(nil), // 19: google.protobuf.BytesValue } var file_complex_proto_depIdxs = []int32{ 2, // 0: testproto.Complex.simple:type_name -> testproto.Simple 0, // 1: testproto.Complex.sex:type_name -> testproto.sex - 5, // 2: testproto.Complex.timestamp:type_name -> google.protobuf.Timestamp - 6, // 3: testproto.Complex.duration:type_name -> google.protobuf.Duration - 7, // 4: testproto.Complex.field:type_name -> google.protobuf.FieldMask - 8, // 5: testproto.Complex.double:type_name -> google.protobuf.DoubleValue - 9, // 6: testproto.Complex.float:type_name -> google.protobuf.FloatValue - 10, // 7: testproto.Complex.int64:type_name -> google.protobuf.Int64Value - 11, // 8: testproto.Complex.int32:type_name -> google.protobuf.Int32Value - 12, // 9: testproto.Complex.uint64:type_name -> google.protobuf.UInt64Value - 13, // 10: testproto.Complex.uint32:type_name -> google.protobuf.UInt32Value - 14, // 11: testproto.Complex.bool:type_name -> google.protobuf.BoolValue - 15, // 12: testproto.Complex.string:type_name -> google.protobuf.StringValue - 16, // 13: testproto.Complex.bytes:type_name -> google.protobuf.BytesValue - 3, // 14: testproto.Complex.map:type_name -> testproto.Complex.MapEntry - 4, // 15: testproto.Complex.map_int64_key:type_name -> testproto.Complex.MapInt64KeyEntry - 16, // [16:16] is the sub-list for method output_type - 16, // [16:16] is the sub-list for method input_type - 16, // [16:16] is the sub-list for extension type_name - 16, // [16:16] is the sub-list for extension extendee - 0, // [0:16] is the sub-list for field type_name + 8, // 2: testproto.Complex.timestamp:type_name -> google.protobuf.Timestamp + 9, // 3: testproto.Complex.duration:type_name -> google.protobuf.Duration + 10, // 4: testproto.Complex.field:type_name -> google.protobuf.FieldMask + 11, // 5: testproto.Complex.double:type_name -> google.protobuf.DoubleValue + 12, // 6: testproto.Complex.float:type_name -> google.protobuf.FloatValue + 13, // 7: testproto.Complex.int64:type_name -> google.protobuf.Int64Value + 14, // 8: testproto.Complex.int32:type_name -> google.protobuf.Int32Value + 15, // 9: testproto.Complex.uint64:type_name -> google.protobuf.UInt64Value + 16, // 10: testproto.Complex.uint32:type_name -> google.protobuf.UInt32Value + 17, // 11: testproto.Complex.bool:type_name -> google.protobuf.BoolValue + 18, // 12: testproto.Complex.string:type_name -> google.protobuf.StringValue + 19, // 13: testproto.Complex.bytes:type_name -> google.protobuf.BytesValue + 6, // 14: testproto.Complex.map:type_name -> testproto.Complex.MapEntry + 7, // 15: testproto.Complex.map_int64_key:type_name -> testproto.Complex.MapInt64KeyEntry + 3, // 16: testproto.Complex.complex_field:type_name -> testproto.ComplexField + 4, // 17: testproto.ComplexField.inner1:type_name -> testproto.Inner1 + 5, // 18: testproto.ComplexField.inner2:type_name -> testproto.Inner2 + 0, // 19: testproto.Inner1.sex:type_name -> testproto.sex + 4, // 20: testproto.Inner2.inner1:type_name -> testproto.Inner1 + 21, // [21:21] is the sub-list for method output_type + 21, // [21:21] is the sub-list for method input_type + 21, // [21:21] is the sub-list for extension type_name + 21, // [21:21] is the sub-list for extension extendee + 0, // [0:21] is the sub-list for field type_name } func init() { file_complex_proto_init() } @@ -527,7 +736,7 @@ func file_complex_proto_init() { return } if !protoimpl.UnsafeEnabled { - file_complex_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + file_complex_proto_msgTypes[0].Exporter = func(v any, i int) any { switch v := v.(*Complex); i { case 0: return &v.state @@ -539,7 +748,7 @@ func file_complex_proto_init() { return nil } } - file_complex_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + file_complex_proto_msgTypes[1].Exporter = func(v any, i int) any { switch v := v.(*Simple); i { case 0: return &v.state @@ -551,6 +760,42 @@ func file_complex_proto_init() { return nil } } + file_complex_proto_msgTypes[2].Exporter = func(v any, i int) any { + switch v := v.(*ComplexField); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_complex_proto_msgTypes[3].Exporter = func(v any, i int) any { + switch v := v.(*Inner1); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_complex_proto_msgTypes[4].Exporter = func(v any, i int) any { + switch v := v.(*Inner2); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } } type x struct{} out := protoimpl.TypeBuilder{ @@ -558,7 +803,7 @@ func file_complex_proto_init() { GoPackagePath: reflect.TypeOf(x{}).PkgPath(), RawDescriptor: file_complex_proto_rawDesc, NumEnums: 1, - NumMessages: 4, + NumMessages: 7, NumExtensions: 0, NumServices: 0, }, diff --git a/internal/testdata/complex/complex.proto b/internal/testdata/complex/complex.proto index 4e20d5a3447..a4262d901c1 100644 --- a/internal/testdata/complex/complex.proto +++ b/internal/testdata/complex/complex.proto @@ -41,6 +41,7 @@ message Complex { map map = 25; map map_int64_key = 26 [json_name = "map_int64_key"]; + ComplexField complex_field = 27; } message Simple { @@ -50,4 +51,20 @@ message Simple { enum sex { man = 0; woman = 1; -} \ No newline at end of file +} + +message ComplexField { + string name = 1; + Inner1 inner1 = 2; + repeated Inner2 inner2 = 3; +} + +message Inner1 { + string name = 1; + sex sex = 2; +} + +message Inner2 { + string name = 1; + repeated Inner1 inner1 = 2; +} From 31c226031ce449d5b37f27d74e591ea7b09d6837 Mon Sep 17 00:00:00 2001 From: lou Date: Tue, 21 Jan 2025 11:43:43 +0800 Subject: [PATCH 2/2] improve code Signed-off-by: lou --- encoding/form/proto_decode.go | 10 +--------- encoding/form/proto_decode_test.go | 9 ++++++--- 2 files changed, 7 insertions(+), 12 deletions(-) diff --git a/encoding/form/proto_decode.go b/encoding/form/proto_decode.go index cb9c1ecb417..3bed384fcf2 100644 --- a/encoding/form/proto_decode.go +++ b/encoding/form/proto_decode.go @@ -35,15 +35,7 @@ func DecodeValues(msg proto.Message, values url.Values) error { } } - data, err := proto.Marshal(dynamicMessage) - if err != nil { - return fmt.Errorf("failed to marshal dynamic message: %v", err) - } - - err = proto.Unmarshal(data, msg) - if err != nil { - return fmt.Errorf("failed to unmarshal: %v", err) - } + proto.Merge(msg, dynamicMessage) return nil } diff --git a/encoding/form/proto_decode_test.go b/encoding/form/proto_decode_test.go index c2c5622dc09..7669c2df80e 100644 --- a/encoding/form/proto_decode_test.go +++ b/encoding/form/proto_decode_test.go @@ -85,7 +85,6 @@ func TestDecodeJsonValues(t *testing.T) { if err != nil { t.Fatal(err) } - fmt.Println(string(data)) // url.ParseQuery("complex_field={"name":"ComplexField", "inner1":{"name":"Inner1"}, "inner2":[{"name":"Inner11", "inner1":[{"name":"Inner111"}]}, {"name":"Inner12", "inner1":[{"name":"Inner121"}, {"name":"Inner122", "sex":"woman"}]}]}") form, err := url.ParseQuery(fmt.Sprintf("complex_field=%s", string(data))) @@ -93,14 +92,18 @@ func TestDecodeJsonValues(t *testing.T) { t.Fatal(err) } - comp := &complex.Complex{} + comp := &complex.Complex{Age: 10} err = DecodeValues(comp, form) if err != nil { t.Fatal(err) } - if reflect.DeepEqual(origin, comp.ComplexField) { + if !reflect.DeepEqual(origin, comp.ComplexField) { t.Errorf("want %v, got %v", origin, comp.ComplexField) } + // check if age is not overridden + if comp.Age != 10 { + t.Errorf("want %v, got %v", "10", comp.Age) + } } func TestGetFieldDescriptor(t *testing.T) {