Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unmarshaling JSON into a UUID type

Tags:

json

go

I'm trying to use the json.Unmarshaler interface to unmarshal a UUID into a uuid.UUID field on a struct. I created a custom type called myUUID and everything works until I try to access methods that are normally on uuid.UUID. How can I handle this? I'm relatively new to Go, so maybe I just don't fully understand custom types just yet.

package main

import (
    "encoding/json"
    "errors"
    "fmt"

    "code.google.com/p/go-uuid/uuid"
)

var jsonstring = `
{
    "uuid": "273b62ad-a99d-48be-8d80-ccc55ef688b4"
}
`

type myUUID uuid.UUID

type Data struct {
    uuid myUUID
}

func (u *myUUID) UnmarshalJson(b []byte) error {
    id := uuid.Parse(string(b[:]))
    if id == nil {
            return errors.New("Could not parse UUID")
    }
    *u = myUUID(id)
    return nil
}

func main() {
    d := new(Data)
    err := json.Unmarshal([]byte(jsonstring), &d)
    if err != nil {
            fmt.Printf("%s", err)
    }
    fmt.Println(d.uuid.String())
}
like image 542
Kyle Avatar asked Aug 12 '14 07:08

Kyle


2 Answers

You might want to make sure your myuuid variable is visible/exported in the Data struct: as in "public".
Same for the type alias MyUUID (instead of myUUID)

type MyUUID uuid.UUID

type Data struct {
    Uuid MyUUID
}

From JSON and Go:

The json package only accesses the exported fields of struct types (those that begin with an uppercase letter).


As commented by Ainar G, the style guide also recommends:

Words in names that are initialisms or acronyms (e.g. "URL" or "NATO") have a consistent case.
For example, "URL" should appear as "URL" or "url" (as in "urlPony", or "URLPony"), never as "Url". Here's an example: ServeHTTP not ServeHttp.

This rule also applies to "ID" when it is short for "identifier," so write "appID" instead of "appId".

In your case, that would mean:

type Data struct {
    UUID MyUUID
}
like image 57
VonC Avatar answered Nov 20 '22 12:11

VonC


Go's custom types don't inherit methods. I refactored the code using a custom struct and attaching an UnmarshalJSON.

import (
        "errors"
        "strings"

        "github.com/pborman/uuid"
)


type ServiceID struct {
    UUID uuid.UUID
}

type Meta struct {
    Name    string `json:"name"`
    Version string `json:"version"`
    SID     *ServiceID `json:"UUID"`
}

func (self *ServiceID) UnmarshalJSON(b []byte) error {
    s := strings.Trim(string(b), "\"")
    self.UUID = uuid.Parse(s)
    if self.UUID == nil {
            return errors.New("Could not parse UUID")
    }
    return nil
}
like image 5
Kyle Avatar answered Nov 20 '22 12:11

Kyle