Documentation ¶
Overview ¶
Package jwriter provides an efficient mechanism for writing JSON data sequentially.
The high-level API for this package, Writer, is designed to facilitate writing custom JSON marshaling logic concisely and reliably. Output is buffered in memory.
import ( "gopkg.in/launchdarkly/jsonstream.v1/jwriter" ) type myStruct struct { value int } func (s myStruct) WriteToJSONWriter(w *jwriter.Writer) { obj := w.Object() // writing a JSON object structure like {"value":2} obj.Property("value").Int(s.value) obj.End() } func PrintMyStructJSON(s myStruct) { w := jwriter.NewWriter() s.WriteToJSONWriter(&w) fmt.Println(string(w.Bytes()) }
Output can optionally be dumped to an io.Writer at intervals to avoid allocating a large buffer:
func WriteToHTTPResponse(s myStruct, resp http.ResponseWriter) { resp.Header.Add("Content-Type", "application/json") w := jwriter.NewStreamingWriter(resp, 1000) myStruct.WriteToJSONWriter(&w) }
The underlying low-level token writing mechanism has two available implementations. The default implementation has no external dependencies. For interoperability with the easyjson library (https://github.com/mailru/easyjson), there is also an implementation that delegates to the easyjson streaming writer; this is enabled by setting the build tag "launchdarkly_easyjson". Be aware that by default, easyjson uses Go's "unsafe" package (https://pkg.go.dev/unsafe), which may not be available on all platforms.
Setting the "launchdarkly_easyjson" tag also adds a new constructor function, NewWriterFromEasyJSONWriter, allowing Writer-based code to send output directly to an existing EasyJSON jwriter.Writer. This may be desirable in order to define common marshaling logic that may be used with or without EasyJSON. For example:
import ( ej_jwriter "github.com/mailru/easyjson/jwriter" ) func (s myStruct) MarshalEasyJSON(w *ej_jwriter.Writer) { ww := jwriter.NewWriterFromEasyJSONWriter(w) s.WriteToJSONWriter(&ww) }
Example ¶
w := NewWriter() obj := w.Object() obj.Name("propertyName").String("propertyValue") obj.End() if err := w.Error(); err != nil { fmt.Println("error:", err.Error()) } else { fmt.Println(string(w.Bytes())) }
Output: {"propertyName":"propertyValue"}
Index ¶
- func MarshalJSONWithWriter(writable Writable) ([]byte, error)
- type ArrayState
- func (arr *ArrayState) Array() ArrayState
- func (arr *ArrayState) Bool(value bool)
- func (arr *ArrayState) End()
- func (arr *ArrayState) Float64(value float64)
- func (arr *ArrayState) Int(value int)
- func (arr *ArrayState) Null()
- func (arr *ArrayState) Object() ObjectState
- func (arr *ArrayState) Raw(value json.RawMessage)
- func (arr *ArrayState) String(value string)
- type ObjectState
- type Writable
- type Writer
- func (w *Writer) AddError(err error)
- func (w *Writer) Array() ArrayState
- func (w *Writer) Bool(value bool)
- func (w *Writer) BoolOrNull(isDefined bool, value bool)
- func (w *Writer) Bytes() []byte
- func (w *Writer) Error() error
- func (w *Writer) Float64(value float64)
- func (w *Writer) Float64OrNull(isDefined bool, value float64)
- func (w *Writer) Flush() error
- func (w *Writer) Int(value int)
- func (w *Writer) IntOrNull(isDefined bool, value int)
- func (w *Writer) Null()
- func (w *Writer) Object() ObjectState
- func (w *Writer) Raw(value json.RawMessage)
- func (w *Writer) String(value string)
- func (w *Writer) StringOrNull(isDefined bool, value string)
Examples ¶
- Package
- ArrayState.Array
- ArrayState.Bool
- ArrayState.Float64
- ArrayState.Int
- ArrayState.Null
- ArrayState.Object
- ArrayState.Raw
- ArrayState.String
- NewStreamingWriter
- NewWriter
- ObjectState.Maybe
- ObjectState.Name
- Writer.AddError
- Writer.Array
- Writer.Bool
- Writer.BoolOrNull
- Writer.Float64
- Writer.Float64OrNull
- Writer.Int
- Writer.IntOrNull
- Writer.Null
- Writer.Object
- Writer.Raw
- Writer.String
- Writer.StringOrNull
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func MarshalJSONWithWriter ¶
MarshalJSONWithWriter is a convenience method for implementing json.Marshaler to marshal to a byte slice with the default TokenWriter implementation.
Types ¶
type ArrayState ¶
type ArrayState struct {
// contains filtered or unexported fields
}
ArrayState is a decorator that manages the state of a JSON array that is in the process of being written.
Calling Writer.Array() or ObjectState.Array() creates an ArrayState. Until ArrayState.End() is called, writing any value to either the ArrayState or the Writer will cause commas to be added between values as needed.
func (*ArrayState) Array ¶
func (arr *ArrayState) Array() ArrayState
Array is equivalent to calling writer.Array(), to create a nested array.
Example ¶
w := NewWriter() arr := w.Array() arr.Int(1) subArr := arr.Array() subArr.Int(2) subArr.Int(3) subArr.End() arr.Int(4) arr.End() fmt.Println(string(w.Bytes()))
Output: [1,[2,3],4]
func (*ArrayState) Bool ¶
func (arr *ArrayState) Bool(value bool)
Bool is equivalent to writer.Bool(value).
Example ¶
w := NewWriter() arr := w.Array() arr.Bool(true) arr.Bool(false) arr.End() fmt.Println(string(w.Bytes()))
Output: [true,false]
func (*ArrayState) End ¶
func (arr *ArrayState) End()
End writes the closing delimiter of the array.
func (*ArrayState) Float64 ¶
func (arr *ArrayState) Float64(value float64)
Float64 is equivalent to writer.Float64(value).
Example ¶
w := NewWriter() arr := w.Array() arr.Float64(1234.5) arr.Float64(6) arr.End() fmt.Println(string(w.Bytes()))
Output: [1234.5,6]
func (*ArrayState) Int ¶
func (arr *ArrayState) Int(value int)
Int is equivalent to writer.Int(value).
Example ¶
w := NewWriter() arr := w.Array() arr.Int(123) arr.Int(456) arr.End() fmt.Println(string(w.Bytes()))
Output: [123,456]
func (*ArrayState) Null ¶
func (arr *ArrayState) Null()
Null is equivalent to writer.Null().
Example ¶
w := NewWriter() arr := w.Array() arr.Null() arr.Null() arr.End() fmt.Println(string(w.Bytes()))
Output: [null,null]
func (*ArrayState) Object ¶
func (arr *ArrayState) Object() ObjectState
Object is equivalent to calling writer.Object(), to create a nested object.
Example ¶
w := NewWriter() arr := w.Array() obj1 := arr.Object() obj1.Name("value").Int(1) obj1.End() obj2 := arr.Object() obj2.Name("value").Int(2) obj2.End() arr.End() fmt.Println(string(w.Bytes()))
Output: [{"value":1},{"value":2}]
func (*ArrayState) Raw ¶
func (arr *ArrayState) Raw(value json.RawMessage)
Raw is equivalent to calling writer.Raw().
Example ¶
data := json.RawMessage(`{"value":1}`) w := NewWriter() arr := w.Array() arr.Raw(data) arr.End() fmt.Println(string(w.Bytes()))
Output: [{"value":1}]
func (*ArrayState) String ¶
func (arr *ArrayState) String(value string)
String is equivalent to writer.String(value).
Example ¶
w := NewWriter() arr := w.Array() arr.String(`string says "hello"`) arr.String("ok") arr.End() fmt.Println(string(w.Bytes()))
Output: ["string says \"hello\"","ok"]
type ObjectState ¶
type ObjectState struct {
// contains filtered or unexported fields
}
ObjectState is a decorator that writes values to an underlying Writer within the context of a JSON object, adding property names and commas between values as appropriate.
func (*ObjectState) End ¶
func (obj *ObjectState) End()
End writes the closing delimiter of the object.
func (*ObjectState) Maybe ¶
func (obj *ObjectState) Maybe(name string, shouldWrite bool) *Writer
Maybe writes an object property name conditionally depending on a boolean parameter. If shouldWrite is true, this behaves the same as Property(name). However, if shouldWrite is false, it does not write a property name and instead of returning the underlying Writer, it returns a stub Writer that does not produce any output. This allows you to chain method calls without having to use an if statement.
obj.Maybe(shouldWeIncludeTheProperty, "myBooleanProperty").Bool(true)
Example ¶
w := NewWriter() obj := w.Object() obj.Maybe("notPresent", false).Int(1) obj.Maybe("present", true).Int(2) obj.End() fmt.Println(string(w.Bytes()))
Output: {"present":2}
func (*ObjectState) Name ¶
func (obj *ObjectState) Name(name string) *Writer
Name writes an object property name and a colon. You can then use Writer methods to write the property value. The return value is the same as the underlying Writer, so you can chain method calls:
obj.Name("myBooleanProperty").Bool(true)
Example ¶
myCustomMarshaler := func(w *Writer) { subObject := w.Object() subObject.Name("yes").Bool(true) subObject.End() } w := NewWriter() obj := w.Object() myCustomMarshaler(obj.Name("subObject")) obj.End() fmt.Println(string(w.Bytes()))
Output: {"subObject":{"yes":true}}
type Writable ¶
type Writable interface { // WriteToJSONWriter writes JSON content to the Writer. // // This method does not need to return an error value. If the Writer encounters an error during output // generation, it will remember its own error state, which can be detected with Writer.Error(). WriteToJSONWriter(*Writer) }
Writable is an interface for types that can write their data to a Writer.
type Writer ¶
type Writer struct {
// contains filtered or unexported fields
}
Writer is a high-level API for writing JSON data sequentially.
It is designed to make writing custom marshallers for application types as convenient as possible. The general usage pattern is as follows:
- There is one method for each JSON data type.
- For writing array or object structures, the Array and Object methods return a struct that keeps track of additional writer state while that structure is being written.
- If any method encounters an error (for instance, if an underlying io.Writer returns an error when using NewStreamingWriter), or if an error is explicitly raised with AddError, the Writer permanently enters a failed state and remembers that error; all subsequent method calls for producing output will be ignored.
func NewStreamingWriter ¶
NewStreamingWriter creates a Writer that will buffer a limited amount of its output in memory and dump the output to the specified io.Writer whenever the buffer is full. You should also call Flush at the end of your output to ensure that any remaining buffered output is flushed.
If the Writer returns an error at any point, it enters a failed state and will not try to write any more data to the target.
This function returns the struct by value (Writer, not *Writer). This avoids the overhead of a heap allocation since, in typical usage, the Writer will not escape the scope in which it was declared and can remain on the stack.
Example ¶
w := NewStreamingWriter(os.Stdout, 10) obj := w.Object() obj.Name("property").String("value") obj.End() w.Flush()
Output: {"property":"value"}
func NewWriter ¶
func NewWriter() Writer
NewWriter creates a Writer that will buffer its entire output in memory.
This function returns the struct by value (Writer, not *Writer). This avoids the overhead of a heap allocation since, in typical usage, the Writer will not escape the scope in which it was declared and can remain on the stack.
Example ¶
w := NewWriter() obj := w.Object() obj.Name("property").String("value") obj.End() fmt.Println(string(w.Bytes()))
Output: {"property":"value"}
func (*Writer) AddError ¶
AddError sets the error state if an error has not already been recorded.
Example ¶
w := NewWriter() obj := w.Object() obj.Name("prop1").Bool(true) w.AddError(errors.New("sorry, we can't serialize this after all")) obj.Name("prop2").Bool(true) // no output is generated here because the Writer has already failed fmt.Println("error is:", w.Error()) fmt.Println("buffer is:", string(w.Bytes()))
Output: error is: sorry, we can't serialize this after all buffer is: {"prop1":true
func (*Writer) Array ¶
func (w *Writer) Array() ArrayState
Array begins writing a JSON array to the output. It returns an ArrayState that provides the array formatting; you must call ArrayState.End() when finished.
Example ¶
w := NewWriter() arr := w.Array() arr.Bool(true) arr.Int(3) arr.End() fmt.Println(string(w.Bytes()))
Output: [true,3]
func (*Writer) Bool ¶
Bool writes a JSON boolean value to the output.
Example ¶
w := NewWriter() w.Bool(true) fmt.Println(string(w.Bytes()))
Output: true
func (*Writer) BoolOrNull ¶
BoolOrNull is a shortcut for calling Bool(value) if isDefined is true, or else Null().
Example ¶
w := NewWriter() w.BoolOrNull(false, true) fmt.Println(string(w.Bytes()))
Output: null
func (*Writer) Error ¶
Error returns the first error, if any, that occurred during output generation. If there have been no errors, it returns nil.
As soon as any operation fails at any level, either in the JSON encoding or in writing to an underlying io.Writer, the Writer remembers the error and will generate no further output.
func (*Writer) Float64 ¶
Float64 writes a JSON numeric value to the output.
Example ¶
w := NewWriter() w.Float64(1234.5) fmt.Println(string(w.Bytes()))
Output: 1234.5
func (*Writer) Float64OrNull ¶
Float64OrNull is a shortcut for calling Float64(value) if isDefined is true, or else Null().
Example ¶
w := NewWriter() w.Float64OrNull(false, 1) fmt.Println(string(w.Bytes()))
Output: null
func (*Writer) Flush ¶
Flush writes any remaining in-memory output to the underlying io.Writer, if this is a streaming writer created with NewStreamingWriter. It has no effect otherwise.
func (*Writer) Int ¶
Int writes a JSON numeric value to the output.
Example ¶
w := NewWriter() w.Int(123) fmt.Println(string(w.Bytes()))
Output: 123
func (*Writer) IntOrNull ¶
IntOrNull is a shortcut for calling Int(value) if isDefined is true, or else Null().
Example ¶
w := NewWriter() w.IntOrNull(false, 1) fmt.Println(string(w.Bytes()))
Output: null
func (*Writer) Null ¶
func (w *Writer) Null()
Null writes a JSON null value to the output.
Example ¶
w := NewWriter() w.Null() fmt.Println(string(w.Bytes()))
Output: null
func (*Writer) Object ¶
func (w *Writer) Object() ObjectState
Object begins writing a JSON object to the output. It returns an ObjectState that provides the object formatting; you must call ObjectState.End() when finished.
Example ¶
w := NewWriter() obj := w.Object() obj.Name("boolProperty").Bool(true) obj.Name("intProperty").Int(3) obj.End() fmt.Println(string(w.Bytes()))
Output: {"boolProperty":true,"intProperty":3}
func (*Writer) Raw ¶
func (w *Writer) Raw(value json.RawMessage)
Raw writes a pre-encoded JSON value to the output as-is. Its format is assumed to be correct; this operation will not fail unless it is not permitted to write a value at this point.
Example ¶
data := json.RawMessage(`{"value":1}`) w := NewWriter() w.Raw(data) fmt.Println(string(w.Bytes()))
Output: {"value":1}