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

json: cannot unmarshal array into Go struct field Attribute.attributes.values of type structpb.Value #1019

Closed
blakecschmidt opened this issue Jan 16, 2020 · 4 comments

Comments

@blakecschmidt
Copy link

What version of protobuf and what language are you using?
Protobuf version 1.3.2
Go version 1.13.5

What did you do?
I am working with the Google My Business API and I am attempting to retrieve the JSON response of a location.
https://developers.google.com/my-business/reference/rest/v4/accounts.locations/get

After retrieving the JSON, I am unmarshaling it as a Location object. This Location object contains an attribute field which is an array of Attribute objects. Within the attribute object is another array of protobuf Values.

In my Go code, I have a .go file containing all of the structs which make up this Location struct. In this file I am importing the following:

import (
	structpb "github.com/golang/protobuf/ptypes/struct"
)

And when I define this Attribute struct I define the Values with the following:

type Attribute struct {
	AttributeId string `json:"attributeId"`
	ValueType AttributeValueType `json:"valueType"`
	Values []structpb.Value `json:"values"`
	RepeatedEnumValue RepeatedEnumAttributeValue `json:"repeatedEnumValue"`
	UrlValues []UrlAttributeValue `json:"urlValues"`
}

The JSON that I am receiving from the GMB API contains the following attributes component:

"attributes": [
    {
      "attributeId": "pay_debit_card",
      "valueType": "BOOL",
      "values": [
        true
      ]
    },
    {
      "attributeId": "has_wheelchair_accessible_elevator",
      "valueType": "BOOL",
      "values": [
        true
      ]
    },
    {
      "attributeId": "has_service_installation",
      "valueType": "BOOL",
      "values": [
        true
      ]
    },
    {
      "attributeId": "pay_check",
      "valueType": "BOOL",
      "values": [
        true
      ]
    },
    {
      "attributeId": "has_delivery_same_day",
      "valueType": "BOOL",
      "values": [
        true
      ]
    },
    {
      "attributeId": "has_gift_wrapping",
      "valueType": "BOOL",
      "values": [
        false
      ]
    },
    {
      "attributeId": "requires_cash_only",
      "valueType": "BOOL",
      "values": [
        false
      ]
    },
    {
      "attributeId": "has_wheelchair_accessible_entrance",
      "valueType": "BOOL",
      "values": [
        true
      ]
    },
    {
      "attributeId": "has_service_repair",
      "valueType": "BOOL",
      "values": [
        true
      ]
    },
    {
      "attributeId": "wi_fi",
      "valueType": "ENUM",
      "values": [
        "free_wi_fi"
      ]
    },
    {
      "attributeId": "pay_credit_card_types_accepted",
      "valueType": "REPEATED_ENUM",
      "repeatedEnumValue": {
        "setValues": [
          "american_express",
          "discover",
          "mastercard",
          "visa"
        ]
      }

The function in which I am receiving this JSON and unmarshaling is:

func GetStore(accessToken string) {
	response, err := http.Get(fmt.Sprintf("%vaccounts/%v/locations/%v?access_token=%v", gmbBaseUri, "104256381367782693902", "10772730936382702757", accessToken))

	if err != nil {
		fmt.Printf("The HTTP request failed with error %s\n", err)
	}
	data, _ := ioutil.ReadAll(response.Body)
	fmt.Println(string(data))
	var location Location
	if err := json.Unmarshal(data, &location); err != nil {
		panic(err)
	}
	fmt.Println(location.Name)
}

What did you expect to see?
If this code was working correctly, my function would correctly unmarshal the JSON into a Location object and it would print out the name of the Location as specified in the JSON.

What did you see instead?
Instead, I am receiving the following error:

panic: json: cannot unmarshal bool into Go struct field Attribute.attributes.values of type structpb.Value

Which fails at the panic(err) line when unmarshaling.

Anything else we should know about your project / environment?
I am running this locally using the GoLand IDE

@puellanivis
Copy link
Collaborator

encoding/json does not understand anything of how to marshal from or unmarshal to golang/protobuf/ptype/struct.Value. The encoding/json library is specifically not supported for marshalling and unmarshalling protobuf data types, because the protobuf JSON mapping standards cannot be complied with through the encoding/json package.

@blakecschmidt
Copy link
Author

@puellanivis Thanks for that information, this makes a lot of sense. I'm assuming this means I just need to use the protobuf jsonpb.Unmarshal() instead? I've been looking at it and am having a little trouble understanding in what way I need to change my code because the arguments seem to be a bit different than what the encoding/json unmarshal wants. Would you be able to shed some light on this for me?

@puellanivis
Copy link
Collaborator

The jsonpb package only knows how to unmarshal protobuf messages, and is not ever intended to unmarshal individual protobuf elements. This means you cannot integrate it into unmarshalling directly into a slice of protobuf objects, since protobuf does not have a concept of a slice outside of the body of a message.

You would likely need to use something like:

	Values []json.RawMessage `json:"values"`

And then jsobpb.Unmarshal each value individually, or define the whole Attribute struct as a protobuf Message somewhere, and then jsonpb.Unmarshal into that.

@blakecschmidt
Copy link
Author

Thanks for the help, I'm probably gonna move forward with that json.RawMessage and if I run into further problems I may just need to set the entire thing as a protobuf message

@golang golang locked and limited conversation to collaborators Jul 23, 2020
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants