diff --git a/json_reader.go b/json_reader.go index f71402e..f242dab 100644 --- a/json_reader.go +++ b/json_reader.go @@ -3,15 +3,17 @@ package jsonconv import ( "encoding/json" "io" + "reflect" + "strings" ) // A JsonReader reads and decodes JSON values from an input stream. type JsonReader struct { - reader io.Reader + reader io.ReadSeeker } // NewJsonReader returns a new JsonReader that reads from r. -func NewJsonReader(r io.Reader) *JsonReader { +func NewJsonReader(r io.ReadSeeker) *JsonReader { return &JsonReader{ reader: r, } @@ -21,11 +23,40 @@ func NewJsonReader(r io.Reader) *JsonReader { // input and stores it in the value pointed to by v. func (r *JsonReader) Read(v interface{}) error { decoder := json.NewDecoder(r.reader) - for decoder.More() { - err := decoder.Decode(v) - if err != nil { + err := decoder.Decode(v) + if err != nil { + if !strings.Contains(err.Error(), "cannot unmarshal object into Go value of type") { return err } + + // The JSON data is a valid JSON array. However, we will try to decode it line by line. + // Reset reader and decoder. + r.reader.Seek(0, io.SeekStart) + decoder = json.NewDecoder(r.reader) + + // Check if v is a pointer to a slice or an array. If not, return an error. + refval := reflect.ValueOf(v) + if refval.Kind() == reflect.Pointer { + refval = refval.Elem() + } + if refval.Kind() != reflect.Slice && refval.Kind() != reflect.Array { + return err + } + + // Decode JSON array into v. + for { + obj := reflect.New(refval.Type().Elem()) + objInterface := obj.Interface() + err := decoder.Decode(objInterface) + if err != nil { + if err == io.EOF { + reflect.ValueOf(v).Elem().Set(refval) + return nil + } + return err + } + refval.Set(reflect.Append(refval, reflect.ValueOf(objInterface).Elem())) + } } return nil } diff --git a/json_reader_test.go b/json_reader_test.go index c213a72..f0df0d9 100644 --- a/json_reader_test.go +++ b/json_reader_test.go @@ -80,7 +80,46 @@ func TestJsonReader_JsonArray(t *testing.T) { } // Check - if len(arr) == 0 { + if len(arr) != 3 { + t.Fatalf("failed to read json array") + } + if arr[0]["id"] != "ce06f5b1-5721-42c0-91e1-9f72a09c250a" || + arr[0]["user"] != "Tuấn" || + arr[0]["score"] != "1.5" || + arr[0]["is active"] != "true" { + t.Fatalf("failed to read json array") + } + if arr[1]["id"] != "b042ab5c-ca73-4460-b739-96410ea9d3a6" || + arr[1]["user"] != "Jon Doe" || + arr[1]["score"] != "-100" || + arr[1]["is active"] != "false" { + t.Fatalf("failed to read json array") + } + if arr[2]["id"] != "4e01b638-44e5-4079-8043-baabbff21cc8" || + arr[2]["user"] != "高橋" || + arr[2]["score"] != "100000000000000000000000" || + arr[2]["is active"] != "true" { + t.Fatalf("failed to read json array") + } +} + +func TestJsonReader_JsonArray_NewlineDelimited(t *testing.T) { + // Prepare + raw := ` + {"id": "ce06f5b1-5721-42c0-91e1-9f72a09c250a","user": "Tuấn","score": "1.5","is active": "true"} + {"id": "b042ab5c-ca73-4460-b739-96410ea9d3a6","user": "Jon Doe","score": "-100","is active": "false"} + {"id": "4e01b638-44e5-4079-8043-baabbff21cc8","user": "高橋","score": "100000000000000000000000","is active": "true"}` + arr := make(JsonArray, 0) + re := NewJsonReader(strings.NewReader(raw)) + + // Process + err := re.Read(&arr) + if err != nil { + t.Fatalf("failed to read file %v", err) + } + + // Check + if len(arr) != 3 { t.Fatalf("failed to read json array") } if arr[0]["id"] != "ce06f5b1-5721-42c0-91e1-9f72a09c250a" ||