Add support for decoding a stream of JSON objects.
Signed-off-by: David Symonds <dsymonds@golang.org>
diff --git a/jsonpb/jsonpb.go b/jsonpb/jsonpb.go
index 768564e..a9e778c 100644
--- a/jsonpb/jsonpb.go
+++ b/jsonpb/jsonpb.go
@@ -428,15 +428,23 @@
return out.err
}
+// UnmarshalNext unmarshals the next protocol buffer from a JSON object stream.
+// This function is lenient and will decode any options permutations of the
+// related Marshaler.
+func UnmarshalNext(dec *json.Decoder, pb proto.Message) error {
+ inputValue := json.RawMessage{}
+ if err := dec.Decode(&inputValue); err != nil {
+ return err
+ }
+ return unmarshalValue(reflect.ValueOf(pb).Elem(), inputValue)
+}
+
// Unmarshal unmarshals a JSON object stream into a protocol
// buffer. This function is lenient and will decode any options
// permutations of the related Marshaler.
func Unmarshal(r io.Reader, pb proto.Message) error {
- inputValue := json.RawMessage{}
- if err := json.NewDecoder(r).Decode(&inputValue); err != nil {
- return err
- }
- return unmarshalValue(reflect.ValueOf(pb).Elem(), inputValue)
+ dec := json.NewDecoder(r)
+ return UnmarshalNext(dec, pb)
}
// UnmarshalString will populate the fields of a protocol buffer based
diff --git a/jsonpb/jsonpb_test.go b/jsonpb/jsonpb_test.go
index 3d70b87..c04da85 100644
--- a/jsonpb/jsonpb_test.go
+++ b/jsonpb/jsonpb_test.go
@@ -32,6 +32,9 @@
package jsonpb
import (
+ "bytes"
+ "encoding/json"
+ "io"
"reflect"
"testing"
@@ -415,6 +418,39 @@
}
}
+func TestUnmarshalNext(t *testing.T) {
+ // Create a buffer with many concatenated JSON objects.
+ var b bytes.Buffer
+ for _, tt := range unmarshalingTests {
+ b.WriteString(tt.json)
+ }
+
+ dec := json.NewDecoder(&b)
+ for _, tt := range unmarshalingTests {
+ // Make a new instance of the type of our expected object.
+ p := reflect.New(reflect.TypeOf(tt.pb).Elem()).Interface().(proto.Message)
+
+ err := UnmarshalNext(dec, p)
+ if err != nil {
+ t.Errorf("%s: %v", tt.desc, err)
+ continue
+ }
+
+ // For easier diffs, compare text strings of the protos.
+ exp := proto.MarshalTextString(tt.pb)
+ act := proto.MarshalTextString(p)
+ if string(exp) != string(act) {
+ t.Errorf("%s: got [%s] want [%s]", tt.desc, act, exp)
+ }
+ }
+
+ p := &pb.Simple{}
+ err := UnmarshalNext(dec, p)
+ if err != io.EOF {
+ t.Errorf("eof: got %v, expected io.EOF", err)
+ }
+}
+
var unmarshalingShouldError = []struct {
desc string
in string