Practical Reflection: Serializers
Building a simple JSON-like serializer with reflect
Practical Reflection: Serializers is a free Go Academy lesson on CoddyKit — lesson 4 of 4. You can read the complete lesson below for free — then practise it hands-on in the browser with a built-in code editor and a 24/7 AI tutor. It is part of the Go Academy learning path, one of 4 lessons in the course, and your progress syncs across the web and the CoddyKit app.
Custom JSON serializer overview
Building a custom serializer with reflection demonstrates practical reflection: iterate struct fields, read tags, access values, and build output — the same approach used by encoding/json internally.
Simple struct-to-map
Convert a struct to a map[string]any using reflection:
func StructToMap(v any) map[string]any {
t := reflect.TypeOf(v)
val := reflect.ValueOf(v)
result := make(map[string]any, t.NumField())
for i := 0; i < t.NumField(); i++ {
f := t.Field(i)
if !f.IsExported() { continue }
key := f.Tag.Get("json")
if key == "" { key = f.Name }
result[key] = val.Field(i).Interface()
}
return result
}Handling pointers
Dereference pointer fields before reading their values:
fv := val.Field(i)
if fv.Kind() == reflect.Ptr {
if fv.IsNil() { continue }
fv = fv.Elem()
}Handling nested structs
Recursively process nested struct fields:
if fv.Kind() == reflect.Struct {
result[key] = StructToMap(fv.Interface())
continue
}omitempty support
Skip zero-value fields if the tag includes "omitempty":
if strings.Contains(tag, "omitempty") && fv.IsZero() { continue }Map-to-struct (deserializer)
Populate a struct from a map by matching map keys to field tags:
func MapToStruct(m map[string]any, dest any) {
t := reflect.TypeOf(dest).Elem()
v := reflect.ValueOf(dest).Elem()
for i := 0; i < t.NumField(); i++ {
key := t.Field(i).Tag.Get("json")
if val, ok := m[key]; ok {
v.Field(i).Set(reflect.ValueOf(val))
}
}
}Type coercion
Map values from JSON are often float64 for numbers. Coerce them to the target field type when setting:
if f.Type.Kind() == reflect.Int && reflect.TypeOf(val).Kind() == reflect.Float64 {
v.Field(i).SetInt(int64(val.(float64)))
}Caching field metadata
Cache the field-to-tag mapping in a sync.Map keyed by reflect.Type to avoid repeated reflection on every serialization call.
Code generation alternative
For performance-critical paths, generate type-specific serialisers with tools like easyjson or ffjson. They avoid runtime reflection entirely.
When to build custom serializers
Custom serializers are useful for: non-JSON formats (BSON, Avro, CSV), custom encoding rules, or tight performance requirements. For most use cases, encoding/json is sufficient.
Testing the serializer
Round-trip test: serialize a struct to map, deserialize back, assert the values match the original:
u := User{Name: "Alice", Age: 30}
m := StructToMap(u)
var u2 User
MapToStruct(m, &u2)
assert.Equal(t, u, u2)Quick Check
Why is field metadata caching important when building a reflection-based serializer?
Recap: Reflection-Based Serializers
Key points:
- Iterate fields with NumField/Field; read tags with Tag.Get
- Handle pointers, nested structs, and zero values
- Cache field metadata in sync.Map for performance
- Use code generation for highest throughput
Frequently asked questions
Is the “Practical Reflection: Serializers” lesson free?
Yes — the full text of “Practical Reflection: Serializers” is free to read here on the web, and the Go Academy course includes 4 lessons in total. To practise it interactively (a built-in code editor and a 24/7 AI tutor) and unlock the rest of the Go Academy course, upgrade to CoddyKit PRO.
What will I learn in “Practical Reflection: Serializers”?
Building a simple JSON-like serializer with reflect You practise Go Academy with hands-on code you run directly in the browser, and a 24/7 AI tutor answers your questions as you work through the lesson.
Do I need any experience to start Go Academy?
No prior experience is required. Go Academy on CoddyKit is structured for beginners through advanced learners; this is — lesson 4 of 4, so you can start here or from the beginning and move at your own pace.
How long does the “Practical Reflection: Serializers” lesson take?
Most CoddyKit lessons take about 5–10 minutes. Each one is bite-sized and interactive, so you make steady progress and pick up exactly where you left off across the web and the app.
Can I write and run code in this Go Academy lesson?
Yes. Every Go Academy lesson includes a built-in code editor, so you write and run real code right in your browser and get instant AI feedback — no local setup required.
All lessons in this course
- reflect.Type and reflect.Value
- Inspecting Struct Fields and Tags
- Dynamic Function Calls
- Practical Reflection: Serializers