serializer
packageAPI reference for the serializer
package.
Imports
(5)sample
type sample struct
Fields
| Name | Type | Description |
|---|---|---|
| FirstName | string | json:"first_name" |
| LastName | string | json:"last_name" |
| Age | int | json:"age" |
TestPolicy_Marshal_SnakeCase
Parameters
func TestPolicy_Marshal_SnakeCase(t *testing.T)
{
p := New(WithNaming(SnakeCase), WithTagName("json"))
s := sample{FirstName: "John", LastName: "Doe", Age: 30}
data, err := p.Marshal(s)
if err != nil {
t.Fatalf("Marshal failed: %v", err)
}
got := string(data)
if !strings.Contains(got, `"first_name":"John"`) || !strings.Contains(got, `"last_name":"Doe"`) || !strings.Contains(got, `"age":30`) {
t.Errorf("Marshal: got %q", got)
}
}
TestPolicy_Unmarshal_SnakeCase
Parameters
func TestPolicy_Unmarshal_SnakeCase(t *testing.T)
{
p := New(WithNaming(SnakeCase), WithTagName("json"))
data := []byte(`{"first_name":"Jane","last_name":"Smith","age":25}`)
var s sample
if err := p.Unmarshal(data, &s); err != nil {
t.Fatalf("Unmarshal failed: %v", err)
}
if s.FirstName != "Jane" {
t.Errorf("FirstName: got %q, want %q", s.FirstName, "Jane")
}
if s.Age != 25 {
t.Errorf("Age: got %d, want %d", s.Age, 25)
}
}
TestPolicy_IgnoreNil
Parameters
func TestPolicy_IgnoreNil(t *testing.T)
{
p := New(WithIgnoreNil(), WithTagName("json"))
type withPtr struct {
Name string `json:"name"`
Score *int `json:"score"`
}
s := withPtr{Name: "test", Score: nil}
data, err := p.Marshal(s)
if err != nil {
t.Fatalf("Marshal failed: %v", err)
}
got := string(data)
if got != `{"name":"test"}` {
t.Errorf("Marshal with IgnoreNil: got %q", got)
}
}
TestPolicy_IgnoreZero
Parameters
func TestPolicy_IgnoreZero(t *testing.T)
{
p := New(WithIgnoreZero(), WithTagName("json"))
type withZero struct {
Name string `json:"name"`
Age int `json:"age"`
}
s := withZero{Name: "test", Age: 0}
data, err := p.Marshal(s)
if err != nil {
t.Fatalf("Marshal failed: %v", err)
}
got := string(data)
if got != `{"name":"test"}` {
t.Errorf("Marshal with IgnoreZero: got %q", got)
}
}
TestPolicy_CamelCase
Parameters
func TestPolicy_CamelCase(t *testing.T)
{
p := New(WithNaming(CamelCase), WithTagName("json"))
type camel struct {
FirstName string
LastName string
}
s := camel{FirstName: "A", LastName: "B"}
data, err := p.Marshal(s)
if err != nil {
t.Fatalf("Marshal failed: %v", err)
}
got := string(data)
if got != `{"firstName":"A","lastName":"B"}` {
t.Errorf("Marshal CamelCase: got %q", got)
}
}
NamingStrategy
NamingStrategy controls how struct field names are transformed during serialization.
type NamingStrategy int
ConverterFactory
ConverterFactory creates a custom type converter for serialization.
type ConverterFactory func() Converter
Policy
Policy defines serialization behavior including naming and custom type handling.
type Policy struct
Methods
Marshal serializes v to JSON bytes using the policy.
Parameters
Returns
func (*Policy) Marshal(v any) ([]byte, error)
{
data, err := p.toMap(v)
if err != nil {
return nil, err
}
return json.Marshal(data)
}
Unmarshal deserializes JSON bytes into v using the policy.
Parameters
Returns
func (*Policy) Unmarshal(data []byte, v any) error
{
var raw map[string]any
if err := json.Unmarshal(data, &raw); err != nil {
return err
}
return p.fromMap(raw, v)
}
MarshalToString serializes v to a JSON string.
Parameters
Returns
func (*Policy) MarshalToString(v any) (string, error)
{
data, err := p.Marshal(v)
if err != nil {
return "", err
}
return string(data), nil
}
Parameters
Returns
func (*Policy) toMap(v any) (map[string]any, error)
{
rv := reflect.ValueOf(v)
if rv.Kind() == reflect.Ptr {
rv = rv.Elem()
}
if rv.Kind() != reflect.Struct {
result := make(map[string]any)
result["value"] = v
return result, nil
}
rt := rv.Type()
result := make(map[string]any)
for i := 0; i < rt.NumField(); i++ {
field := rt.Field(i)
if !field.IsExported() {
continue
}
fv := rv.Field(i)
if p.ignoreNil && fv.Kind() == reflect.Ptr && fv.IsNil() {
continue
}
if p.ignoreZero && fv.IsZero() {
continue
}
name := p.fieldName(field)
result[name] = fv.Interface()
}
return result, nil
}
Parameters
Returns
func (*Policy) fromMap(raw map[string]any, v any) error
{
rv := reflect.ValueOf(v)
if rv.Kind() != reflect.Ptr || rv.Elem().Kind() != reflect.Struct {
return json.Unmarshal(mustJSON(raw), v)
}
elem := rv.Elem()
rt := elem.Type()
for i := 0; i < rt.NumField(); i++ {
field := rt.Field(i)
if !field.IsExported() {
continue
}
name := p.fieldName(field)
if val, ok := raw[name]; ok {
fv := elem.Field(i)
if fv.CanSet() {
setValue(fv, val)
}
}
}
return nil
}
Parameters
Returns
func (*Policy) fieldName(field reflect.StructField) string
{
if tag := field.Tag.Get(p.tagName); tag != "" {
parts := strings.Split(tag, ",")
if parts[0] != "" {
return parts[0]
}
}
return transformName(field.Name, p.naming)
}
Fields
| Name | Type | Description |
|---|---|---|
| naming | NamingStrategy | |
| ignoreNil | bool | |
| ignoreZero | bool | |
| customTypes | map[reflect.Type]ConverterFactory | |
| tagName | string | |
| mu | sync.RWMutex |
Option
Option configures a Policy.
type Option func(*Policy)
New
New creates a Policy with the given options.
Parameters
Returns
func New(opts ...Option) *Policy
{
p := &Policy{
naming: PascalCase,
tagName: "json",
customTypes: make(map[reflect.Type]ConverterFactory),
}
for _, opt := range opts {
opt(p)
}
return p
}
WithNaming
WithNaming sets the naming strategy.
Parameters
Returns
func WithNaming(n NamingStrategy) Option
{
return func(p *Policy) { p.naming = n }
}
WithIgnoreNil
WithIgnoreNil skips nil pointers during marshaling.
Returns
func WithIgnoreNil() Option
{
return func(p *Policy) { p.ignoreNil = true }
}
Uses
WithIgnoreZero
WithIgnoreZero skips zero values during marshaling.
Returns
func WithIgnoreZero() Option
{
return func(p *Policy) { p.ignoreZero = true }
}
Uses
WithTagName
WithTagName sets the struct tag used for field names (default: “json”).
Parameters
Returns
func WithTagName(tag string) Option
{
return func(p *Policy) { p.tagName = tag }
}
Uses
WithCustomType
WithCustomType registers a custom converter for a specific type.
Parameters
Returns
func WithCustomType(typ reflect.Type, factory ConverterFactory) Option
{
return func(p *Policy) { p.customTypes[typ] = factory }
}
transformName
Parameters
Returns
func transformName(name string, strategy NamingStrategy) string
{
switch strategy {
case SnakeCase:
return toSnake(name)
case CamelCase:
return toCamel(name)
default:
return name
}
}
toSnake
Parameters
Returns
func toSnake(s string) string
{
var result strings.Builder
for i, r := range s {
if i > 0 && r >= 'A' && r <= 'Z' {
result.WriteByte('_')
}
result.WriteRune(r)
}
return strings.ToLower(result.String())
}
toCamel
Parameters
Returns
func toCamel(s string) string
{
if len(s) == 0 {
return s
}
return strings.ToLower(s[:1]) + s[1:]
}
setValue
Parameters
func setValue(fv reflect.Value, val any)
{
if val == nil {
return
}
rv := reflect.ValueOf(val)
if rv.Type().ConvertibleTo(fv.Type()) {
fv.Set(rv.Convert(fv.Type()))
}
}
mustJSON
Parameters
Returns
func mustJSON(v any) []byte
{
data, _ := json.Marshal(v)
return data
}