Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

encoding/json: MarshalJSON isn't called for fields of a non-pointer struct #7536

Closed
gopherbot opened this issue Mar 13, 2014 · 2 comments

Comments

Projects
None yet
3 participants
@gopherbot
Copy link

commented Mar 13, 2014

by timothy.stranex:

$ go version
go version go1.2 darwin/amd64

Here is a link to a program on play.golang.org that demonstrates the problem.
http://play.golang.org/p/HXNEgYhZgE

For reference, this is the program:

-------
package main

import "encoding/json"
import "fmt"

type DecimalE8 int64

func (d *DecimalE8) MarshalJSON() ([]byte, error) {
    return []byte(fmt.Sprintf("%.8f", float64(*d) / 1e8)), nil
}

type Payment struct {
    Amount DecimalE8
}

func main() {
    var p Payment
    p.Amount = 123456789

    s1, _ := json.Marshal(p)
    fmt.Println(string(s1))

    s2, _ := json.Marshal(&p)
    fmt.Println(string(s2))
}
-------

The actual output from this program is:
{"Amount":123456789}
{"Amount":1.23456789}

The expected output is:
{"Amount":1.23456789}
{"Amount":1.23456789}

Basically it seems that DecimalE8.MarshalJSON isn't being used when the struct is passed
as a value to json.Marshal but it is used when it's passed as a pointer. I would expect
that DecimalE8.MarshalJSON be used in both cases.
@fraenkel

This comment has been minimized.

Copy link
Contributor

commented Mar 16, 2014

Comment 1:

The behavior looks correct.
If you change your MarshalJSON to the following you will get your expected behavior.
func (d DecimalE8) MarshalJSON() ([]byte, error) {
    return []byte(fmt.Sprintf("%.8f", float64(d) / 1e8)), nil
}
@adg

This comment has been minimized.

Copy link
Contributor

commented Mar 31, 2014

Comment 2:

The language specifies that if *T implements the methods of an interface I then only a
*T (pointer) value will satisfy I, and not a T (value) value. So encoding/json can't see
that *DecimalE8 implements MarshalJSON because it only has a DecimalE8 value.
It is important to preserve this property, because a value implemented on *T might
assume that it can modify the underlying T value (which, given a value receiver, it
could not).

Status changed to WorkingAsIntended.

@golang golang locked and limited conversation to collaborators Jun 25, 2016

This issue was closed.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
You can’t perform that action at this time.