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: struct field implementing Unmarshaler #2170

Closed
gopherbot opened this issue Aug 22, 2011 · 18 comments
Closed

encoding/json: struct field implementing Unmarshaler #2170

gopherbot opened this issue Aug 22, 2011 · 18 comments
Milestone

Comments

@gopherbot
Copy link

by akunokuroneko:

What steps will reproduce the problem?
1. Create a custom type that implements Unmarshaller against it's immediate (not
pointer) value.
2. Use type as an exported immediate value in a struct.
3. json.Decode() and watch the unmarshal fail.

What is the expected output?
The Unmarshaller method to be invoked.

What do you see instead?
"json: cannot unmarshal string into Go value of type ..."

(in this case, string is the literal type being used in the JSON stream to fudge the
custom type)

Which compiler are you using (5g, 6g, 8g, gccgo)?
6g

Which operating system are you using?
Linux amd64

Which revision are you using?  (hg identify)
r59

Please provide any additional information below.
Patch attached.

Attachments:

  1. json-unmarshal-immediate.diff (799 bytes)
@robpike
Copy link
Contributor

robpike commented Aug 22, 2011

Comment 1:

I believe that you shouldn't define Unmarshal that way because it modifies the receiver,
but I'll let rsc respond.

Owner changed to @rsc.

Status changed to Accepted.

@gopherbot
Copy link
Author

Comment 2 by akunokuroneko:

I'm only using it this way against single value types (such as those defined ala: "type
Foob uint64") in order to allow me to forcibly alter the way specific fields are
marshaled and unmarshaled without having to reimplement the struct marshaler.
Primarily I'm using this for textual representations in JSON for what are effectively
enums.

@gopherbot
Copy link
Author

Comment 3 by akunokuroneko:

After further consideration, You're quite right - this method doesn't quite work the way
I envisaged because the receiver is passed by value.  I'll see if I can fix this
correctly.

@gopherbot
Copy link
Author

Comment 4 by akunokuroneko:

Corrected patch to actually do the right thing:
Checks CanAddr() to see if a pointer can be acquired, and then checks to see if an
Unmarshaler is available for pointers to that type.  Failing that, does the usual logic.

Attachments:

  1. json-unmarshal-immediate.diff (604 bytes)

@edsrzf
Copy link

edsrzf commented Aug 22, 2011

Comment 5:

Marshal has the same problem.

@gopherbot
Copy link
Author

Comment 6 by akunokuroneko:

Marshal does the right thing actually if you define the MarshalJSON message on the type
itself rather than a pointer to the type, and already knows to follow pointers to find a
valid type.

@edsrzf
Copy link

edsrzf commented Aug 22, 2011

Comment 7:

I ran into a case recently where it didn't work, but I didn't test thoroughly. I'll take
another look.

@edsrzf
Copy link

edsrzf commented Aug 23, 2011

Comment 8:

I have a simple case that reproduces the problem I was having. Maybe should be a
separate issue.
package main
import (
    "fmt"
    "json"
    "os"
)
type T int
func (t *T) MarshalJSON() ([]byte, os.Error) {
    return []byte(`"T"`), nil
}
func main() {
    var t struct{T T}
    b, _ := json.Marshal(&t)
    fmt.Printf("%s\n", b)
}
The output is
{"T": 0}
I expect
{"T": "T"}

@rsc
Copy link
Contributor

rsc commented Oct 6, 2011

Comment 9:

Status changed to HelpWanted.

@gopherbot
Copy link
Author

Comment 10 by Leo.LVEB:

This is a patch for the second issue, it just checks if *T is a Marshaler.

Attachments:

  1. patch.diff (1299 bytes)

@rsc
Copy link
Contributor

rsc commented Dec 9, 2011

Comment 11:

Labels changed: added priority-later.

@rsc
Copy link
Contributor

rsc commented Dec 12, 2011

Comment 12:

Labels changed: added priority-go1.

@robpike
Copy link
Contributor

robpike commented Jan 13, 2012

Comment 13:

Owner changed to builder@golang.org.

@rsc
Copy link
Contributor

rsc commented Jan 24, 2012

Comment 14:

Still broken.

@rsc
Copy link
Contributor

rsc commented Jan 30, 2012

Comment 15:

Labels changed: added go1-must.

@dsymonds
Copy link
Contributor

dsymonds commented Feb 1, 2012

Comment 16:

I can take a look at this.

Owner changed to @dsymonds.

Status changed to Accepted.

@dsymonds
Copy link
Contributor

dsymonds commented Feb 2, 2012

Comment 17:

Status changed to Started.

@dsymonds
Copy link
Contributor

dsymonds commented Feb 3, 2012

Comment 18:

This issue was closed by revision bf89d58.

Status changed to Fixed.

@rsc rsc added this to the Go1 milestone Apr 10, 2015
@golang golang locked and limited conversation to collaborators Jun 24, 2016
This issue was closed.
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Projects
None yet
Development

No branches or pull requests

5 participants