tailscale.comtailscale.com/types/jsonx Index | Files

package jsonx

import "tailscale.com/types/jsonx"

Package jsonx contains helper types and functionality to use with github.com/go-json-experiment/json, which is positioned to be merged into the Go standard library as encoding/json/v2.

See https://go.dev/issues/71497

Index

Functions

func MakeInterfaceCoders

func MakeInterfaceCoders[T any](valuesByName map[string]T) (c struct {
	Marshal   func(*jsontext.Encoder, *T) error
	Unmarshal func(*jsontext.Decoder, *T) error
})

MakeInterfaceCoders constructs a pair of marshal and unmarshal functions to serialize a Go interface type T. A bijective mapping for the set of concrete types that implement T is provided, where the key is a stable type name to use in the JSON representation, while the value is any value of a concrete type that implements T. By convention, only the zero value of concrete types is passed.

The JSON representation for a dynamic value is a JSON object with a single member, where the member name is the type name, and the value is the JSON representation for the Go value. For example, the JSON serialization for a concrete type named Foo would be {"Foo": ...}, where ... is the JSON representation of the concrete value of the Foo type.

Example instantiation:

// Interface is a union type implemented by [FooType] and [BarType].
type Interface interface { ... }

var interfaceCoders = MakeInterfaceCoders(map[string]Interface{
	"FooType": FooType{},
	"BarType": (*BarType)(nil),
})

The pair of Marshal and Unmarshal functions can be used with the json package with either type-specified or caller-specified serialization. The result of this constructor is usually stored into a global variable.

Example usage with type-specified serialization:

// InterfaceWrapper is a concrete type that wraps [Interface].
// It extends [Interface] to implement
// [json.MarshalerTo] and [json.UnmarshalerFrom].
type InterfaceWrapper struct{ Interface }

func (w InterfaceWrapper) MarshalJSONTo(enc *jsontext.Encoder) error {
	return interfaceCoders.Marshal(enc, &w.Interface)
}

func (w *InterfaceWrapper) UnmarshalJSONFrom(dec *jsontext.Decoder) error {
	return interfaceCoders.Unmarshal(dec, &w.Interface)
}

Example usage with caller-specified serialization:

var opts json.Options = json.JoinOptions(
	json.WithMarshalers(json.MarshalToFunc(interfaceCoders.Marshal)),
	json.WithUnmarshalers(json.UnmarshalFromFunc(interfaceCoders.Unmarshal)),
)

var v Interface
... := json.Marshal(v, opts)
... := json.Unmarshal(&v, opts)

The function panics if T is not a named interface kind, or if valuesByName contains distinct entries with the same concrete type.

Source Files

json.go

Version
v1.84.0 (latest)
Published
May 21, 2025
Platform
linux/amd64
Imports
5 packages
Last checked
1 day ago

Tools for package owners.