Need Help with CustomMarshaler
cpunion opened this issue · comments
Hello,
I'm working with a data structure, which is intended to be flexible and may represent various user-defined structures. Here's an example structure:
type A struct {
ID int
X, Y int
Dependent *A
Children []*A
}
a := &A{
ID: 1,
X: 1,
Y: 2,
}
b := &A{
ID: 2,
X: 3,
Y: 4,
}
c := &A{
ID: 3,
X: 5,
Y: 6,
Children: []*A{
a,
},
Dependent: &A{
ID: 4,
X: 7,
Y: 8,
Dependent: &A{
ID: 5,
X: 9,
Y: 10,
},
},
}
I need to serialize this tree structure in a flattened structure, all references to objects only store their type/id. For example:
- type: a
id: 3
x: 5
y: 6
children:
- type: a
id: 1
dependent:
type: a
id: 4
- type: a
id: 4
x: 7
y: 8
dependent:
type: a
id: 5
- type: a
id: 5
x: 9
y: 10
- type: a
id: 1
x: 1
y: 2
- type: a
id: 2
x: 3
y: 4
I have been using the CustomMarshaler
. My goal is to serialize the first-level objects normally, but for nested objects, return only type/id and queue them for delayed serialization. The challenge is to determine within the CustomMarshaler when an object is at the first level (i.e., the initial call of MarshalWithOptions
to our CustomMarshaler) to serialize its simple fields (not sure how to accomplish this), while returning type/id for referenced fields.
Could anyone provide insights or approaches for handling this situation? Any help on how to effectively implement this type of serialization would be greatly appreciated.
Thank you!
Currently, I have replaced the types of Dependency
and Children
in my structure with the IComponent
interface, and it seems to be working well. This change allows CustomMarshaler[ []IComponent ]
and CustomMarshaler[IComponent]
to handle the lazy serialization of the Children
and Dependency
fields. Meanwhile, the real type A
is being marshaled using reflection. However, if all types are the actual type A
, the outcome is either entirely returning type/id
for each or serializing them all.
I need a CustomMarshaler
like this:
func Serialize(a any) ([]byte, error) {
encodeOption := yaml.CustomMarshaler(func(a *A) ([]byte, error) {
if a == currentRootObject {
// FIXME: this line will cause infinite recursion
return yaml.MarshalWithOptions(a, encodeOption)
} else {
return yaml.Marshal(&RefObject{
Type: "A",
Id: a.ID,
})
}
})
return yaml.MarshalWithOptions(a, encodeOption)
}