From fbed685c37c84bac7a062d894bb3ae7243be6162 Mon Sep 17 00:00:00 2001 From: James Stephenson Date: Fri, 16 Apr 2021 09:47:21 -0400 Subject: [PATCH] Fixing unmarshalling of `numberOrString` New unmarshalling rules for fields which could be numeric or string values were not properly typecasted upon being deserialized. Cleaned up the api template file and moved custom unmarshalling type logic into go code out of the template. --- fields/api.go.tmpl | 35 +++++++++++++++------------------ fields/main.go | 33 ++++++++++++++++++++++++------- unifi/channel_plan.generated.go | 3 +++ unifi/device.generated.go | 3 +++ 4 files changed, 48 insertions(+), 26 deletions(-) diff --git a/fields/api.go.tmpl b/fields/api.go.tmpl index 9e87892..bded5ff 100644 --- a/fields/api.go.tmpl +++ b/fields/api.go.tmpl @@ -2,22 +2,19 @@ {{ define "field" }} {{ .FieldName }} {{ if .IsArray }}[]{{end}}{{ .FieldType }} `json:"{{ .JSONName }}{{ if .OmitEmpty }},omitempty{{ end }}"` {{ if .FieldValidation }}// {{ .FieldValidation }}{{ end }} {{- end }} -{{ define "field-emptyStringInt" }} - {{- if ne .FieldType "int" }}{{else}} - {{ .FieldName }} {{ if .IsArray }}[]{{end}}emptyStringInt `json:"{{ .JSONName }}{{ if .OmitEmpty }}{{ end }}"`{{ end }} {{- end }} -{{ define "field-numberOrString" }} - {{- /* this is kind of a hack, probably a better way to do this when looking at the normalized validation */ -}} - {{- if and (eq .FieldType "string") (or (eq .JSONName "channel") (eq .JSONName "backup_channel") (eq .JSONName "tx_power")) }} - {{ .FieldName }} {{ if .IsArray }}[]{{end}}numberOrString `json:"{{ .JSONName }}{{ if .OmitEmpty }}{{ end }}"`{{ end }} {{- end }} +{{ define "field-customUnmarshalType" }} + {{- if eq .CustomUnmarshalType "" }}{{else}} + {{ .FieldName }} {{ if .IsArray }}[]{{end}}{{ .CustomUnmarshalType }} `json:"{{ .JSONName }}{{ if .OmitEmpty }}{{ end }}"`{{ end }} {{- end }} {{ define "typecast" }} - {{- if eq .FieldType "int" }}{{- if .IsArray }} - dst.{{ .FieldName }}= make([]int, len(aux.{{ .FieldName }})) - for i, v := range aux.{{ .FieldName }} { - dst.{{ .FieldName }}[i] = int(v) - } - {{- else }} - dst.{{ .FieldName }} = int(aux.{{ .FieldName }}) - {{- end }}{{- end }}{{- end }} + {{- if eq .CustomUnmarshalType "" }}{{else}} + {{- if .IsArray }} + dst.{{ .FieldName }}= make([]{{ .FieldType }}, len(aux.{{ .FieldName }})) + for i, v := range aux.{{ .FieldName }} { + dst.{{ .FieldName }}[i] = {{ .FieldType }}(v) + } + {{- else }} + dst.{{ .FieldName }} = {{ .FieldType }}(aux.{{ .FieldName }}) + {{- end }}{{- end }}{{- end }} {{ define "field-embed" }} {{ .FieldName }} {{ if .IsArray }}[]{{end}}{{ if not .Fields }}{{ .FieldType }}{{ else }}struct { {{ range $fk, $fv := .Fields }}{{ if not $fv }} @@ -58,8 +55,8 @@ type {{ $k }} struct { func (dst *{{ $k }}) UnmarshalJSON(b []byte) error { type Alias {{ $k }} aux := &struct { - {{- range $fk, $fv := $v.Fields }}{{ if not $fv }} - {{- else }}{{- template "field-emptyStringInt" $fv }}{{- template "field-numberOrString" $fv }}{{ end }}{{- end }} + {{- range $fk, $fv := $v.Fields }}{{ if not $fv }} + {{- else }}{{- template "field-customUnmarshalType" $fv }}{{ end }}{{- end }} *Alias }{ @@ -71,8 +68,8 @@ func (dst *{{ $k }}) UnmarshalJSON(b []byte) error { return fmt.Errorf("unable to unmarshal alias: %w", err) } - {{- range $fk, $fv := $v.Fields }}{{ if not $fv }} - {{- else }}{{- template "typecast" $fv }}{{ end }}{{ end }} + {{- range $fk, $fv := $v.Fields }}{{ if not $fv }} + {{- else }}{{- template "typecast" $fv }}{{ end }}{{ end }} return nil } diff --git a/fields/main.go b/fields/main.go index 9ee9d8f..6bc162b 100644 --- a/fields/main.go +++ b/fields/main.go @@ -98,13 +98,14 @@ type Resource struct { } type FieldInfo struct { - FieldName string - JSONName string - FieldType string - FieldValidation string - OmitEmpty bool - IsArray bool - Fields map[string]*FieldInfo + FieldName string + JSONName string + FieldType string + FieldValidation string + OmitEmpty bool + IsArray bool + Fields map[string]*FieldInfo + CustomUnmarshalType string } func NewResource(structName string, resourcePath string) *Resource { @@ -278,6 +279,16 @@ func main() { } return nil } + case "ChannelPlan": + resource.FieldProcessor = func(name string, f *FieldInfo) error { + switch name { + case "Channel", "BackupChannel", "TxPower": + if f.FieldType == "string" { + f.CustomUnmarshalType = "numberOrString" + } + } + return nil + } case "Device": resource.FieldProcessor = func(name string, f *FieldInfo) error { switch name { @@ -285,6 +296,11 @@ func main() { f.FieldType = "float64" case "StpPriority", "Ht": f.FieldType = "string" + f.CustomUnmarshalType = "" + case "Channel", "BackupChannel", "TxPower": + if f.FieldType == "string" { + f.CustomUnmarshalType = "numberOrString" + } } f.OmitEmpty = true @@ -294,6 +310,7 @@ func main() { resource.FieldProcessor = func(name string, f *FieldInfo) error { if strings.HasSuffix(name, "Timeout") && name != "ArpCacheTimeout" { f.FieldType = "int" + f.CustomUnmarshalType = "emptyStringInt" } return nil } @@ -304,6 +321,7 @@ func main() { f.FieldType = "bool" case "LastSeen": f.FieldType = "int" + f.CustomUnmarshalType = "emptyStringInt" } return nil } @@ -416,6 +434,7 @@ func (r *Resource) fieldInfoFromValidation(name string, validation interface{}) omitEmpty = true fieldInfo, err = NewFieldInfo(fieldName, name, "int", fieldValidation, omitEmpty, false), nil + fieldInfo.CustomUnmarshalType = "emptyStringInt" return fieldInfo, r.FieldProcessor(fieldName, fieldInfo) } } diff --git a/unifi/channel_plan.generated.go b/unifi/channel_plan.generated.go index b13e369..ccb2929 100644 --- a/unifi/channel_plan.generated.go +++ b/unifi/channel_plan.generated.go @@ -133,6 +133,9 @@ func (dst *ChannelPlanRadioTable) UnmarshalJSON(b []byte) error { if err != nil { return fmt.Errorf("unable to unmarshal alias: %w", err) } + dst.BackupChannel = string(aux.BackupChannel) + dst.Channel = string(aux.Channel) + dst.TxPower = string(aux.TxPower) dst.Width = int(aux.Width) return nil diff --git a/unifi/device.generated.go b/unifi/device.generated.go index ab608eb..5aaea2e 100644 --- a/unifi/device.generated.go +++ b/unifi/device.generated.go @@ -315,9 +315,12 @@ func (dst *DeviceRadioTable) UnmarshalJSON(b []byte) error { } dst.AntennaGain = int(aux.AntennaGain) dst.AntennaID = int(aux.AntennaID) + dst.BackupChannel = string(aux.BackupChannel) + dst.Channel = string(aux.Channel) dst.Maxsta = int(aux.Maxsta) dst.MinRssi = int(aux.MinRssi) dst.SensLevel = int(aux.SensLevel) + dst.TxPower = string(aux.TxPower) return nil }