9

How do I unmarshal a JSON to a struct which contains 2 fields (UserName and Name) containing the same JSON Tag Name (name)?

package main

import (
    "encoding/json"
    "fmt"
)

type User struct {
    UserName string `json:"name,omitempty"`
    Name     string `json:"name,omitempty"`
}

func main() {
    data := []byte(`
                {
                    "name":"kishore"
                }
            `)
    user := &User{}
    err := json.Unmarshal(data, &user)
    if err != nil {
        panic(err)
    }
    fmt.Printf("value of user : %+v\n", user)
}

Actual Output: value of user : &{UserName: Name:}

Expected Output: value of user : &{UserName:kishore Name:kishore}

How do I get the UserName and Name field Populated with kishore?

When I look at the source code of Json I see they discard if 2 top level fields have same tag name. But this comment in code made me think if there is a way to tag both either both tagged or neither tagged

func dominantField(fields []field) (field, bool) {
    // The fields are sorted in increasing index-length order, then by presence of tag.
    // That means that the first field is the dominant one. We need only check
    // for error cases: two fields at top level, either both tagged or neither tagged.
    if len(fields) > 1 && len(fields[0].index) == len(fields[1].index) && fields[0].tag == fields[1].tag {
        return field{}, false
    }
    return fields[0], true
}

Playground Link : https://play.golang.org/p/TN9IQ8lFR6a

6
  • Any reason for the down votes? Is the question missing some required info or Am I missing something obvious? Commented Jun 17, 2020 at 13:31
  • It's in the docs. Unmarshal says: "To unmarshal JSON into a struct, Unmarshal matches incoming object keys to the keys used by Marshal", and Marshal says: "If there is exactly one field (tagged or not according to the first rule), that is selected...Otherwise there are multiple fields, and all are ignored" Commented Jun 17, 2020 at 14:13
  • Put another way: encoding/json does not support multiple struct fields for the same JSON key. You'll have to do this yourself, either by implementing UnmarshalJSON, or by unmarshaling into one field and copying to the other yourself. However, I would very very strongly recommend a thorough code review, because there should be no situation where you actually need the described behavior if the design is correct. Commented Jun 17, 2020 at 14:15
  • @Adrian got it, so its not possible using a json marshaler. Actually there is a situation where this is needed for us. The same Name field gets stored in multiple fields with each having a different operation performed on them. The tags drive the operation on those fields, so before the tag operation kicks in we need all related fields to already be populated with that value. Commented Jun 17, 2020 at 14:25
  • Not sure what you mean "before the tag operation kicks in" - struct field tags are compile-time, not run-time, they're not an "operation" and they don't execute. Commented Jun 17, 2020 at 15:51

2 Answers 2

4
type User struct {
    UserName string `json:"name,omitempty"`
    Name     string `json:"-"`
}

func (u *User) UnmarshalJSON(data []byte) error {
    type U User
    if err := json.Unmarshal(data, (*U)(u)); err != nil {
        return err
    }
    u.Name = u.UserName
    return nil
}

https://play.golang.org/p/PRuigiBfwWv

Sign up to request clarification or add additional context in comments.

1 Comment

I actually can't add methods to my struct (As this is dynamically created struct using reflection). Also, the manual assignment might become messy as there are about 4 fields which will have these duplicate tags and the only access I've to fields of this object is via reflection. The struct can contain nested object like []Dependents who internally will have duplicate tags with in that struct.
2

This is actually a case of duplicate struct tags causing unmarshaller to ignore it. As per the official documentation - "3) Otherwise there are multiple fields, and all are ignored; no error occurs."

https://golang.org/pkg/encoding/json/

What you should probably do is "go vet" and see if your code has such issues.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.