英文:
How to ignore MarshalJSON implementation of a struct (with nested structs)?
问题
可以忽略自定义的MarshalJSON
实现,而只使用标准的编组函数吗?
这个结构体很复杂,有很多嵌套的结构体,它们都使用自定义的MarshalJSON
,我想忽略它们。
我觉得这应该很简单。你有什么想法吗?
一些细节
显而易见的解决方案是创建一个新类型,但这并不适用于嵌套的结构体,它们仍然使用它们自己的MarshalJSON
。
这是代码的一个示例:
func (de DeploymentExtended) MarshalJSON() ([]byte, error) {
objectMap := make(map[string]interface{})
if de.Location != nil {
objectMap["location"] = de.Location
}
if de.Properties != nil {
objectMap["properties"] = de.Properties
}
if de.Tags != nil {
objectMap["tags"] = de.Tags
}
return json.Marshal(objectMap)
}
(来源:https://github.com/Azure/azure-sdk-for-go/blob/v62.0.0/services/resources/mgmt/2020-10-01/resources/models.go#L366)
还有很多属性(如Name
等),我希望在我的JSON中看到它们(对于Properties
和其他嵌套的结构体也是如此)。
这段代码的Python实现提供了这些数据,我的软件使用它,我(将代码移植到Go)也希望能够从我的Go程序中导出这些数据。
英文:
Is it possible to ignore a custom MarshalJSON
implementation of a struct,
and use just standard marshaling function instead?
The struct is complex, and has a lot of nested structs, all of which are
using custom MarshalJSON
, and I would like to ignore them all.
I feel that it should be trivial. Do you have an idea?
Some details
An obvious solution with a new type creation does not work well, because the nested structs still use their MarshalJSON
s.
Here is an example of the code:
func (de DeploymentExtended) MarshalJSON() ([]byte, error) {
objectMap := make(map[string]interface{})
if de.Location != nil {
objectMap["location"] = de.Location
}
if de.Properties != nil {
objectMap["properties"] = de.Properties
}
if de.Tags != nil {
objectMap["tags"] = de.Tags
}
return json.Marshal(objectMap)
}
And there are a lot of properties (like Name
, etc), which I would like to see in my JSON (the same for Properties
and other nested structs).
The Python implementation of this code provides that data, my software use it, and I (porting the code to Go) would like to be able to export these data from my Go program too.
答案1
得分: 2
你可以通过两种方式来实现:
- 自定义类型(隐藏
MarshalJSON
方法); - 自定义编组器(在运行时使用
reflect
忽略任何MarshalJSON
方法)。
自定义类型
例如,考虑以下嵌套类型:
type Y struct {
FieldZ string
}
type X struct {
Name string
Y Y
}
func (x *X) MarshalJSON() ([]byte, error) { return []byte(`"不想要这个"`), nil }
func (y *Y) MarshalJSON() ([]byte, error) { return []byte(`"绝对不想要这个"`), nil }
为了避免调用不需要的MarshalJSON
方法,需要创建这些类型的影子类型:
type shadowY struct {
FieldZ string
}
type shadowX struct {
Name string
Y shadowY
}
//
// 将原始的 'x' 转换为使用我们的影子类型
//
x2 := shadowX{
Name: x.Name,
Y: shadowY(x.Y),
}
https://go.dev/play/p/vzKtb0gZZov
反射
下面是一个基于reflect
的简单JSON编组器,可以实现你想要的效果。它假设所有自定义编组器都使用指针接收器,并对指针进行解引用,以便标准库的json.Marshal
不会"看到"它们:
func MyJSONMarshal(v interface{}) (bs []byte, err error) {
k := reflect.TypeOf(v).Kind() // 指针还是非指针?
if k != reflect.Ptr {
return json.Marshal(v)
}
// 解引用指针
v2 := reflect.ValueOf(v).Elem().Interface()
return MyJSONMarshal(v2)
}
使用此方法时,请注意你的情况可能会有所不同。
https://go.dev/play/p/v9YjYRno7RV
英文:
You can do this two ways:
- custom types (to hide the
MarshalJSON
methods); or - custom marshaler (using
reflect
to ignore anyMarshalJSON
methods at runtime)
Custom Types
For example, take these nested types:
type Y struct {
FieldZ string
}
type X struct {
Name string
Y Y
}
func (x *X) MarshalJSON() ([]byte, error) { return []byte(`"DONT WANT THIS"`), nil }
func (y *Y) MarshalJSON() ([]byte, error) { return []byte(`"DEFINITELY DONT WANT THIS"`), nil }
one would need to shadow these types to avoid the unwanted MarshalJSON
methods from being invoked:
type shadowY struct {
FieldZ string
}
type shadowX struct {
Name string
Y shadowY
}
//
// transform original 'x' to use our shadow types
//
x2 := shadowX{
Name: x.Name,
Y: shadowY(x.Y),
}
https://go.dev/play/p/vzKtb0gZZov
Reflection
Here's a simple reflect
-based JSON marshaler to achieve what you want. It assumes that all the custom marshalers use pointer receivers - and dereferences the pointer so the standard library's json.Marshal
will not "see" them:
func MyJSONMarshal(v interface{}) (bs []byte, err error) {
k := reflect.TypeOf(v).Kind() // ptr or not?
if k != reflect.Ptr {
return json.Marshal(v)
}
// dereference pointer
v2 := reflect.ValueOf(v).Elem().Interface()
return MyJSONMarshal(v2)
}
YMMV with this method.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论