I'm relatively new to GoLang, and am having trouble with the strict typing system (I'm much more used to weakly typed languages).
In trying to write a Alexa SmartHome skill I need to create the JSON structures defined (eg) at https://developer.amazon.com/en-US/docs/alexa/device-apis/alexa-contactsensor.html
The StateReport Response is where I start to have trouble, in particular with the context.
The example looks like:
"context": {
"properties": [
{
"namespace": "Alexa.ContactSensor",
"name": "detectionState",
"value": "NOT_DETECTED",
"timeOfSample": "2017-02-03T16:20:50.52Z",
"uncertaintyInMilliseconds": 0
},
{
"namespace": "Alexa.EndpointHealth",
"name": "connectivity",
"value": {
"value": "OK"
},
"timeOfSample": "2017-02-03T16:20:50.52Z",
"uncertaintyInMilliseconds": 0
}
]
}
At first glance this looks simple enough:
Context struct {
Properties []struct {
Namespace string `json:"namespace"`
Name string `json:"name"`
Value string `json:"value"`
Timeofsample time.Time `json:"timeOfSample"`
Uncertaintyinmilliseconds int `json:"uncertaintyInMilliseconds"`
} `json:"properties"`
} `json:"context"`
But the "Value" field is where I have the problem.
In the first element of the array we have a simple string
"value": "NOT_DETECTED",
but the second element is a structure
"value": {
"value": "OK"
},
(This doesn't seem to be a typo in the docs; it's repeated at https://developer.amazon.com/en-US/docs/alexa/device-apis/alexa-endpointhealth.html and elsewhere as well).
And this is where the strict typing of GoLang and my knowledge of the language begins to defeat me.
How can I model this value
element, since it doesn't seem to have a fixed type?
Or is there a better way of doing this?
Create a type like this:
import (
"bytes"
"encoding/json"
"fmt"
)
// nullOK is a JSON OK literal
var nullOK = []byte("OK")
type ValueString struct {
Error string
Valid bool
}
// UnmarshalJSON implements json.Unmarshaler.
func (s *ValueString) UnmarshalJSON(data []byte) error {
if bytes.Equal(data, nullOK) {
s.Valid = true
return nil
}
if err := json.Unmarshal(data, &s.Error); err != nil {
return fmt.Errorf("checking OK: couldn't unmarshal JSON: %w", err)
}
s.Valid = false
return nil
}
// MarshalJSON implements json.Marshaler.
func (s ValueString) MarshalJSON() ([]byte, error) {
if s.Valid {
return []byte("OK"), nil
}
return json.Marshal(s.Error)
}
And use it in your struct:
...
Value ValueString `json:"value"`
...
When value is "OK" your Value.Valid
will be true
, else check the Value.Error
for parsed value.
Using the hint from mkopriva I think I came up with simple proof of concept solution using interface{}
and anonymous structures
package main
import "encoding/json"
import "fmt"
type Foo struct {
Value interface{} `json:"value"`
}
func main() {
v1 := Foo{Value: "version1"}
j1, _ := json.Marshal(v1)
fmt.Println(string(j1))
v2 := Foo{Value: struct {
Value string `json:"value"`
}{Value: "version2"}}
j2, _ := json.Marshal(v2)
fmt.Println(string(j2))
}
Running this gives the two ouputs:
{"value":"version1"}
{"value":{"value":"version2"}}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.