0

If I have some JSON data like this:

{
  nullableID: ""
}

How can I get unmarshalling this struct:

help := struct {
  ID *primitive.ObjectID `json:"nullableID",omitempty`
}{}

To decode into help such that help.ID == nil

Flimzy
  • 68,325
  • 15
  • 126
  • 165
Aidan Rosswood
  • 1,162
  • 1
  • 9
  • 21
  • If that's what you really want to do, set the `UnmarshalJSON` method on `primitive.ObjectID` to do that. But this smells like an [XY Problem](http://xyproblem.info/). What is the actual problem to be solved? – Flimzy Oct 03 '19 at 19:43
  • 2
    And note that your struct tag is invalid. It should be `json:"nullableID,omitempty"` – Flimzy Oct 03 '19 at 19:43
  • 1
    Possible duplicate https://stackoverflow.com/q/31048557/13860 – Flimzy Oct 03 '19 at 19:44
  • It's more an "is there an easy way to do this" type of question. I understand I can parse the request object as a string and then make a new struct while converting those string to `primitive.ObjectID`s its just a bunch of lines and tons of `if err != nil`s that I would like to avoid – Aidan Rosswood Oct 03 '19 at 19:49
  • A custom unmarshaler should be maybe 3 lines, or 5 max. – Flimzy Oct 04 '19 at 07:18
  • But more important: why? Are you sure this is even needed? – Flimzy Oct 04 '19 at 07:18
  • No, a custom unmarshaller is not needed since this is a one-off which is only because old mobile clients are sending an empty string instead of null. I wanted to know if there was some tag like "omitempty" that could do what I wanted with a few characters. – Aidan Rosswood Oct 05 '19 at 01:46
  • 1
    No, there's no tag to do this. A custom unmarshaler is the idiomatic approach. – Flimzy Oct 05 '19 at 09:17

1 Answers1

2

Have ObjectID implement the Unmarshaler interface and check for an empty string:

func (o *ObjectID) UnmarshalJSON(data []byte) error {
  if err := json.Unmarshal(data, o); err != nil {
    return err
  }
  if string(*o) == "" {
    o = nil
  }
  return nil
}

If the ObjectID type is imported from another package, you can create a new type that wraps that type:

// objID is a copy of primitive.ObjectID but with it's own json unmarshalling.
type objID struct {
  *primitive.ObjectID
}

func (o *objID) UnmarshalJSON(data []byte) error {
  // Same implementation as above
}

This article explains it in a lot more detail.

17xande
  • 1,940
  • 20
  • 32
  • That code won't even compile. `o == ""` is invalid. – Flimzy Oct 05 '19 at 09:18
  • @Flimzy I’m not sure what the type of ObjectId is, you’ll probably have to cast it to a string before you compare it. ‘if string(o) == “”’ – 17xande Oct 06 '19 at 10:05
  • I'm not sure what type `ObjectId` is either, except that it's a pointer, and a pointer will never `== ""`. `string(o) == ""` will also never work on a pointer. – Flimzy Oct 06 '19 at 17:35
  • You're right, I didn't try to run the code. I added a cast and a de-reference. That code won't be right for every type, but I tried to keep it short and simple for the simplest case here. – 17xande Oct 07 '19 at 11:48