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

Comments

Projects
None yet
5 participants
@gopherbot
Copy link

commented Aug 22, 2011

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

This comment has been minimized.

Copy link
Contributor

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

This comment has been minimized.

Copy link
Author

commented Aug 22, 2011

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

This comment has been minimized.

Copy link
Author

commented Aug 22, 2011

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

This comment has been minimized.

Copy link
Author

commented Aug 22, 2011

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

This comment has been minimized.

Copy link

commented Aug 22, 2011

Comment 5:

Marshal has the same problem.
@gopherbot

This comment has been minimized.

Copy link
Author

commented Aug 22, 2011

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

This comment has been minimized.

Copy link

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

This comment has been minimized.

Copy link

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

This comment has been minimized.

Copy link
Contributor

commented Oct 6, 2011

Comment 9:

Status changed to HelpWanted.

@gopherbot

This comment has been minimized.

Copy link
Author

commented Oct 25, 2011

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

This comment has been minimized.

Copy link
Contributor

commented Dec 9, 2011

Comment 11:

Labels changed: added priority-later.

@rsc

This comment has been minimized.

Copy link
Contributor

commented Dec 12, 2011

Comment 12:

Labels changed: added priority-go1.

@robpike

This comment has been minimized.

Copy link
Contributor

commented Jan 13, 2012

Comment 13:

Owner changed to builder@golang.org.

@rsc

This comment has been minimized.

Copy link
Contributor

commented Jan 24, 2012

Comment 14:

Still broken.
@rsc

This comment has been minimized.

Copy link
Contributor

commented Jan 30, 2012

Comment 15:

Labels changed: added go1-must.

@dsymonds

This comment has been minimized.

Copy link
Member

commented Feb 1, 2012

Comment 16:

I can take a look at this.

Owner changed to @dsymonds.

Status changed to Accepted.

@dsymonds

This comment has been minimized.

Copy link
Member

commented Feb 2, 2012

Comment 17:

Status changed to Started.

@dsymonds

This comment has been minimized.

Copy link
Member

commented Feb 3, 2012

Comment 18:

This issue was closed by revision bf89d58.

Status changed to Fixed.

@gopherbot gopherbot added fixed labels Feb 3, 2012

@rsc rsc added this to the Go1 milestone Apr 10, 2015

@rsc rsc removed priority-go1 labels 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.
You can’t perform that action at this time.