Home > Blockchain >  How to ignore MarshalJSON implementation of a struct (with nested structs)?
How to ignore MarshalJSON implementation of a struct (with nested structs)?

Time:03-03

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 MarshalJSONs.

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)
}

(source: https://github.com/Azure/azure-sdk-for-go/blob/v62.0.0/services/resources/mgmt/2020-10-01/resources/models.go#L366)

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.

CodePudding user response:

You can do this two ways:

  • custom types (to hide the MarshalJSON methods); or
  • custom marshaler (using reflect to ignore any MarshalJSON 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.

https://go.dev/play/p/v9YjYRno7RV

  • Related