jsoninline is a small Go utility that helps inline nested struct fields into the parent object when marshaling to JSON. It provides InlineMarshaler and a helper V() to wrap values that should be inlined.
Features
- Inline fields tagged with
,inlineinto their parent JSON object. - Support for pointers, structs, slices/arrays, and basic types.
Installation
go get github.com/hydrz/jsoninline@latestQuick start
- Use
jsoninline.InlineMarshaleras the field type and add,inlineto the JSON tag. - Wrap a value with
jsoninline.V(value)to mark it for inlining. - Marshal using the standard
encoding/jsonpackage.
Example
package main
import (
"encoding/json"
"fmt"
"github.com/hydrz/jsoninline"
)
type DNSServerOption struct {
Type string `json:"type"`
Tag string `json:"tag"`
Local LocalDNSServerOption `json:",inline"`
UDP UDPDNSServerOption `json:",inline"`
TLS TLSDNSServerOption `json:",inline"`
}
type LocalDNSServerOption struct {
PreferGO bool `json:"prefer_go,omitempty"`
}
type ServerOptions struct {
Server string `json:"server,omitempty"`
ServerPort int `json:"server_port,omitempty"`
}
type UDPDNSServerOption struct {
ServerOptions
}
type TLSDNSServerOption struct {
ServerOptions
TLS any `json:"tls,omitempty"`
}
func main() {
options := []DNSServerOption{
{
Type: "local",
Tag: "local-dns",
Local: LocalDNSServerOption{
PreferGO: true,
},
},
{
Type: "udp",
Tag: "udp-dns",
UDP: UDPDNSServerOption{
ServerOptions: ServerOptions{
Server: "1.1.1.1",
ServerPort: 53,
},
},
},
{
Type: "tls",
Tag: "tls-dns",
TLS: TLSDNSServerOption{
ServerOptions: ServerOptions{
Server: "dns.google",
ServerPort: 853,
},
TLS: map[string]interface{}{
"sni": "dns.google",
},
},
},
}
bytes, err := json.MarshalIndent(jsoninline.V(options), "", " ")
if err != nil {
panic(err)
}
fmt.Println(string(bytes))
// Output:
// [ ... ]
}Unmarshal example
You can also use jsoninline.V when unmarshaling to populate structs that expect inlined fields. Example:
//go:build example
package main
import (
"encoding/json"
"fmt"
"github.com/hydrz/jsoninline"
)
// Demonstrates unmarshaling JSON with inlined fields into Go structs
// using jsoninline.V to wrap the destination.
type User struct {
ID int `json:"id"`
Name string `json:"name"`
Email string `json:"email"`
China *China `json:",inline"`
USA *USA `json:",inline"`
}
func (u *User) String() string {
data, _ := json.Marshal(jsoninline.V(u))
return string(data)
}
type China struct {
City string `json:"city,omitempty"`
Province string `json:"province,omitempty"`
}
type USA struct {
City string `json:"city,omitempty"`
State string `json:"state,omitempty"`
}
var jsonData = `[
{
"id": 1,
"name": "Alice",
"email": "alice@example.com",
"province": "Guangdong",
"city": "Shenzhen"
},
{
"id": 2,
"name": "Bob",
"email": "bob@example.com",
"state": "California",
"city": "Los Angeles"
}
]`
func main() {
var users []*User
if err := json.Unmarshal([]byte(jsonData), jsoninline.V(&users)); err != nil {
panic(err)
}
for i, u := range users {
fmt.Printf("user %d: %+v\n", i, u)
}
// Output:
// user 0: { ... }
}JSON Schema Usage
package main
import (
"encoding/json"
"fmt"
"github.com/google/jsonschema-go/jsonschema"
"github.com/hydrz/jsoninline"
)
// Example types mirroring test fixtures; used to demonstrate schema generation.
type User struct {
ID int `json:"id"`
Name string `json:"name"`
Email string `json:"email"`
China *China `json:",inline"`
USA *USA `json:",inline"`
}
type China struct {
City string `json:"city,omitempty"`
Province string `json:"province,omitempty"`
NestedFoo *NestedFoo `json:",inline"`
}
type USA struct {
City string `json:"city,omitempty"`
State string `json:"state,omitempty"`
NestedBar *NestedBar `json:",inline"`
}
type NestedFoo struct {
FooField string `json:"foo_field,omitempty"`
}
type NestedBar struct {
BarField string `json:"bar_field,omitempty"`
}
func main() {
schema, err := jsoninline.For[User](&jsonschema.ForOptions{})
if err != nil {
panic(err)
}
// Marshal the schema to pretty JSON and print it.
b, err := json.MarshalIndent(schema, "", " ")
if err != nil {
panic(err)
}
fmt.Println(string(b))
}