Skip to content

Commit 951a149

Browse files
authored
proto: deprecate {Unm,M}arshalMessageSet{JSON} (#741)
Despite the naming, these are "internal-only" functions that are intended to only be called from generated code for MessageSets. Furthermore, MessageSets are themselves a deprecated feature from proto1 days, such that descriptor.proto even warns against their use since the initial open-source release of protocol buffers in 2008. Within Google, there are no direct usages of these functions, and all existing usages of MessageSets go through the new table-driven implementation. In addition to deprecating the {Unm,M}arshalMessageSet{JSON} top-level functions, also modify the generator to stop emitting MarshalJSON and UnmarshalJSON methods for messages sets. The UnmarshalJSON method is not implemented and the MarshalJSON method does not seem to be called anywhere in Google (verified by making the method panic and doing a global test). The jsonpb package continues to work with MessageSets. I should note that when the table-driven implementation was open sourced in late 2017 (see 8cc9e46), it accidentally removed generation of the Marshal and Unmarshal method. However, no one seemed to have noticed that those methods were no longer generated.
1 parent 75dceb1 commit 951a149

File tree

9 files changed

+72
-208
lines changed

9 files changed

+72
-208
lines changed

proto/deprecated.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,33 @@
3131

3232
package proto
3333

34+
import "errors"
35+
3436
// Deprecated: do not use.
3537
type Stats struct{ Emalloc, Dmalloc, Encode, Decode, Chit, Cmiss, Size uint64 }
3638

3739
// Deprecated: do not use.
3840
func GetStats() Stats { return Stats{} }
41+
42+
// Deprecated: do not use.
43+
func MarshalMessageSet(interface{}) ([]byte, error) {
44+
return nil, errors.New("proto: not implemented")
45+
}
46+
47+
// Deprecated: do not use.
48+
func UnmarshalMessageSet([]byte, interface{}) error {
49+
return errors.New("proto: not implemented")
50+
}
51+
52+
// Deprecated: do not use.
53+
func MarshalMessageSetJSON(interface{}) ([]byte, error) {
54+
return nil, errors.New("proto: not implemented")
55+
}
56+
57+
// Deprecated: do not use.
58+
func UnmarshalMessageSetJSON([]byte, interface{}) error {
59+
return errors.New("proto: not implemented")
60+
}
61+
62+
// Deprecated: do not use.
63+
func RegisterMessageSetType(Message, int32, string) {}

proto/message_set.go

Lines changed: 2 additions & 135 deletions
Original file line numberDiff line numberDiff line change
@@ -36,13 +36,7 @@ package proto
3636
*/
3737

3838
import (
39-
"bytes"
40-
"encoding/json"
4139
"errors"
42-
"fmt"
43-
"reflect"
44-
"sort"
45-
"sync"
4640
)
4741

4842
// errNoMessageTypeID occurs when a protocol buffer does not have a message type ID.
@@ -145,46 +139,9 @@ func skipVarint(buf []byte) []byte {
145139
return buf[i+1:]
146140
}
147141

148-
// MarshalMessageSet encodes the extension map represented by m in the message set wire format.
149-
// It is called by generated Marshal methods on protocol buffer messages with the message_set_wire_format option.
150-
func MarshalMessageSet(exts interface{}) ([]byte, error) {
151-
return marshalMessageSet(exts, false)
152-
}
153-
154-
// marshaMessageSet implements above function, with the opt to turn on / off deterministic during Marshal.
155-
func marshalMessageSet(exts interface{}, deterministic bool) ([]byte, error) {
156-
switch exts := exts.(type) {
157-
case *XXX_InternalExtensions:
158-
var u marshalInfo
159-
siz := u.sizeMessageSet(exts)
160-
b := make([]byte, 0, siz)
161-
return u.appendMessageSet(b, exts, deterministic)
162-
163-
case map[int32]Extension:
164-
// This is an old-style extension map.
165-
// Wrap it in a new-style XXX_InternalExtensions.
166-
ie := XXX_InternalExtensions{
167-
p: &struct {
168-
mu sync.Mutex
169-
extensionMap map[int32]Extension
170-
}{
171-
extensionMap: exts,
172-
},
173-
}
174-
175-
var u marshalInfo
176-
siz := u.sizeMessageSet(&ie)
177-
b := make([]byte, 0, siz)
178-
return u.appendMessageSet(b, &ie, deterministic)
179-
180-
default:
181-
return nil, errors.New("proto: not an extension map")
182-
}
183-
}
184-
185-
// UnmarshalMessageSet decodes the extension map encoded in buf in the message set wire format.
142+
// unmarshalMessageSet decodes the extension map encoded in buf in the message set wire format.
186143
// It is called by Unmarshal methods on protocol buffer messages with the message_set_wire_format option.
187-
func UnmarshalMessageSet(buf []byte, exts interface{}) error {
144+
func unmarshalMessageSet(buf []byte, exts interface{}) error {
188145
var m map[int32]Extension
189146
switch exts := exts.(type) {
190147
case *XXX_InternalExtensions:
@@ -222,93 +179,3 @@ func UnmarshalMessageSet(buf []byte, exts interface{}) error {
222179
}
223180
return nil
224181
}
225-
226-
// MarshalMessageSetJSON encodes the extension map represented by m in JSON format.
227-
// It is called by generated MarshalJSON methods on protocol buffer messages with the message_set_wire_format option.
228-
func MarshalMessageSetJSON(exts interface{}) ([]byte, error) {
229-
var m map[int32]Extension
230-
switch exts := exts.(type) {
231-
case *XXX_InternalExtensions:
232-
var mu sync.Locker
233-
m, mu = exts.extensionsRead()
234-
if m != nil {
235-
// Keep the extensions map locked until we're done marshaling to prevent
236-
// races between marshaling and unmarshaling the lazily-{en,de}coded
237-
// values.
238-
mu.Lock()
239-
defer mu.Unlock()
240-
}
241-
case map[int32]Extension:
242-
m = exts
243-
default:
244-
return nil, errors.New("proto: not an extension map")
245-
}
246-
var b bytes.Buffer
247-
b.WriteByte('{')
248-
249-
// Process the map in key order for deterministic output.
250-
ids := make([]int32, 0, len(m))
251-
for id := range m {
252-
ids = append(ids, id)
253-
}
254-
sort.Sort(int32Slice(ids)) // int32Slice defined in text.go
255-
256-
for i, id := range ids {
257-
ext := m[id]
258-
msd, ok := messageSetMap[id]
259-
if !ok {
260-
// Unknown type; we can't render it, so skip it.
261-
continue
262-
}
263-
264-
if i > 0 && b.Len() > 1 {
265-
b.WriteByte(',')
266-
}
267-
268-
fmt.Fprintf(&b, `"[%s]":`, msd.name)
269-
270-
x := ext.value
271-
if x == nil {
272-
x = reflect.New(msd.t.Elem()).Interface()
273-
if err := Unmarshal(ext.enc, x.(Message)); err != nil {
274-
return nil, err
275-
}
276-
}
277-
d, err := json.Marshal(x)
278-
if err != nil {
279-
return nil, err
280-
}
281-
b.Write(d)
282-
}
283-
b.WriteByte('}')
284-
return b.Bytes(), nil
285-
}
286-
287-
// UnmarshalMessageSetJSON decodes the extension map encoded in buf in JSON format.
288-
// It is called by generated UnmarshalJSON methods on protocol buffer messages with the message_set_wire_format option.
289-
func UnmarshalMessageSetJSON(buf []byte, exts interface{}) error {
290-
// Common-case fast path.
291-
if len(buf) == 0 || bytes.Equal(buf, []byte("{}")) {
292-
return nil
293-
}
294-
295-
// This is fairly tricky, and it's not clear that it is needed.
296-
return errors.New("TODO: UnmarshalMessageSetJSON not yet implemented")
297-
}
298-
299-
// A global registry of types that can be used in a MessageSet.
300-
301-
var messageSetMap = make(map[int32]messageSetDesc)
302-
303-
type messageSetDesc struct {
304-
t reflect.Type // pointer to struct
305-
name string
306-
}
307-
308-
// RegisterMessageSetType is called from the generated code.
309-
func RegisterMessageSetType(m Message, fieldNum int32, name string) {
310-
messageSetMap[fieldNum] = messageSetDesc{
311-
t: reflect.TypeOf(m),
312-
name: name,
313-
}
314-
}

proto/message_set_test.go

Lines changed: 44 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -29,49 +29,60 @@
2929
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
3030
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3131

32-
package proto
32+
package proto_test
3333

3434
import (
3535
"bytes"
36+
"fmt"
3637
"testing"
38+
39+
"github.com/golang/protobuf/proto"
40+
. "github.com/golang/protobuf/proto/test_proto"
3741
)
3842

3943
func TestUnmarshalMessageSetWithDuplicate(t *testing.T) {
40-
// Check that a repeated message set entry will be concatenated.
41-
in := &messageSet{
42-
Item: []*_MessageSet_Item{
43-
{TypeId: Int32(12345), Message: []byte("hoo")},
44-
{TypeId: Int32(12345), Message: []byte("hah")},
45-
},
46-
}
47-
b, err := Marshal(in)
48-
if err != nil {
49-
t.Fatalf("Marshal: %v", err)
50-
}
51-
t.Logf("Marshaled bytes: %q", b)
44+
/*
45+
Message{
46+
Tag{1, StartGroup},
47+
Message{
48+
Tag{2, Varint}, Uvarint(12345),
49+
Tag{3, Bytes}, Bytes("hoo"),
50+
},
51+
Tag{1, EndGroup},
52+
Tag{1, StartGroup},
53+
Message{
54+
Tag{2, Varint}, Uvarint(12345),
55+
Tag{3, Bytes}, Bytes("hah"),
56+
},
57+
Tag{1, EndGroup},
58+
}
59+
*/
60+
var in []byte
61+
fmt.Sscanf("0b10b9601a03686f6f0c0b10b9601a036861680c", "%x", &in)
5262

53-
var extensions XXX_InternalExtensions
54-
if err := UnmarshalMessageSet(b, &extensions); err != nil {
55-
t.Fatalf("UnmarshalMessageSet: %v", err)
56-
}
57-
ext, ok := extensions.p.extensionMap[12345]
58-
if !ok {
59-
t.Fatalf("Didn't retrieve extension 12345; map is %v", extensions.p.extensionMap)
60-
}
61-
// Skip wire type/field number and length varints.
62-
got := skipVarint(skipVarint(ext.enc))
63-
if want := []byte("hoohah"); !bytes.Equal(got, want) {
64-
t.Errorf("Combined extension is %q, want %q", got, want)
65-
}
66-
}
63+
/*
64+
Message{
65+
Tag{1, StartGroup},
66+
Message{
67+
Tag{2, Varint}, Uvarint(12345),
68+
Tag{3, Bytes}, Bytes("hoohah"),
69+
},
70+
Tag{1, EndGroup},
71+
}
72+
*/
73+
var want []byte
74+
fmt.Sscanf("0b10b9601a06686f6f6861680c", "%x", &want)
6775

68-
func TestMarshalMessageSetJSON_UnknownType(t *testing.T) {
69-
extMap := map[int32]Extension{12345: Extension{}}
70-
got, err := MarshalMessageSetJSON(extMap)
76+
var m MyMessageSet
77+
if err := proto.Unmarshal(in, &m); err != nil {
78+
t.Fatalf("unexpected Unmarshal error: %v", err)
79+
}
80+
got, err := proto.Marshal(&m)
7181
if err != nil {
72-
t.Fatalf("MarshalMessageSetJSON: %v", err)
82+
t.Fatalf("unexpected Marshal error: %v", err)
7383
}
74-
if want := []byte("{}"); !bytes.Equal(got, want) {
75-
t.Errorf("MarshalMessageSetJSON(%v) = %q, want %q", extMap, got, want)
84+
85+
if !bytes.Equal(got, want) {
86+
t.Errorf("output mismatch:\ngot %x\nwant %x", got, want)
7687
}
7788
}

proto/table_unmarshal.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ func (u *unmarshalInfo) unmarshal(m pointer, b []byte) error {
136136
u.computeUnmarshalInfo()
137137
}
138138
if u.isMessageSet {
139-
return UnmarshalMessageSet(b, m.offset(u.extensions).toExtensions())
139+
return unmarshalMessageSet(b, m.offset(u.extensions).toExtensions())
140140
}
141141
var reqMask uint64 // bitmask of required fields we've seen.
142142
var errLater error

proto/test_proto/test.pb.go

Lines changed: 0 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

protoc-gen-go/generator/generator.go

Lines changed: 0 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -2408,17 +2408,6 @@ func (g *Generator) generateCommonMethods(mc *msgCtx) {
24082408

24092409
// Extension support methods
24102410
if len(mc.message.ExtensionRange) > 0 {
2411-
// message_set_wire_format only makes sense when extensions are defined.
2412-
if opts := mc.message.Options; opts != nil && opts.GetMessageSetWireFormat() {
2413-
g.P()
2414-
g.P("func (m *", mc.goName, ") MarshalJSON() ([]byte, error) {")
2415-
g.P("return ", g.Pkg["proto"], ".MarshalMessageSetJSON(&m.XXX_InternalExtensions)")
2416-
g.P("}")
2417-
g.P("func (m *", mc.goName, ") UnmarshalJSON(buf []byte) error {")
2418-
g.P("return ", g.Pkg["proto"], ".UnmarshalMessageSetJSON(buf, &m.XXX_InternalExtensions)")
2419-
g.P("}")
2420-
}
2421-
24222411
g.P()
24232412
g.P("var extRange_", mc.goName, " = []", g.Pkg["proto"], ".ExtensionRange{")
24242413
for _, r := range mc.message.ExtensionRange {
@@ -2824,10 +2813,8 @@ func (g *Generator) generateExtension(ext *ExtensionDescriptor) {
28242813
// In addition, the situation for when to apply this special case is implemented
28252814
// differently in other languages:
28262815
// https://github.com/google/protobuf/blob/aff10976/src/google/protobuf/text_format.cc#L1560
2827-
mset := false
28282816
if extDesc.GetOptions().GetMessageSetWireFormat() && typeName[len(typeName)-1] == "message_set_extension" {
28292817
typeName = typeName[:len(typeName)-1]
2830-
mset = true
28312818
}
28322819

28332820
// For text formatting, the package must be exactly what the .proto file declares,
@@ -2849,10 +2836,6 @@ func (g *Generator) generateExtension(ext *ExtensionDescriptor) {
28492836
g.P()
28502837

28512838
g.addInitf("%s.RegisterExtension(%s)", g.Pkg["proto"], ext.DescName())
2852-
if mset {
2853-
// Generate a bit more code to register with message_set.go.
2854-
g.addInitf("%s.RegisterMessageSetType((%s)(nil), %d, %q)", g.Pkg["proto"], fieldType, *field.Number, extName)
2855-
}
28562839

28572840
g.file.addExport(ext, constOrVarSymbol{ccTypeName, "var", ""})
28582841
}

protoc-gen-go/testdata/extension_base/extension_base.pb.go

Lines changed: 0 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

protoc-gen-go/testdata/extension_user/extension_user.pb.go

Lines changed: 0 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

protoc-gen-go/testdata/my_test/test.pb.go

Lines changed: 0 additions & 7 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)