Tengo una estructura como esta:
type Result struct {
Data MyStruct `json:"data,omitempty"`
Status string `json:"status,omitempty"`
Reason string `json:"reason,omitempty"`
}
Pero incluso si la instancia de MyStruct está completamente vacía (es decir, todos los valores son predeterminados), se serializa como:
"data":{}
Sé que los documentos de codificación / json especifican que los campos "vacíos" son:
falso, 0, cualquier puntero nulo o valor de interfaz, y cualquier matriz, sector, mapa o cadena de longitud cero
pero sin tener en cuenta una estructura con todos los valores vacíos / predeterminados. Todos sus campos también están etiquetados con omitempty
, pero esto no tiene ningún efecto.
¿Cómo puedo hacer que el paquete JSON no clasifique mi campo que es una estructura vacía?
&MyStruct{ /* values */ }
cuenta como un puntero nulo? El valor no es nulo.Como @chakrit mencionado en un comentario, usted no puede conseguir que esto funcione mediante la implementación
json.Marshaler
deMyStruct
, y la implementación de una función de clasificación JSON personalizado en cada estructura que los usos que pueden ser mucho más trabajo. Realmente depende de su caso de uso en cuanto a si vale la pena el trabajo adicional o si está preparado para vivir con estructuras vacías en su JSON, pero aquí está el patrón que uso aplicado aResult
:type Result struct { Data MyStruct Status string Reason string } func (r Result) MarshalJSON() ([]byte, error) { return json.Marshal(struct { Data *MyStruct `json:"data,omitempty"` Status string `json:"status,omitempty"` Reason string `json:"reason,omitempty"` }{ Data: &r.Data, Status: r.Status, Reason: r.Reason, }) } func (r *Result) UnmarshalJSON(b []byte) error { decoded := new(struct { Data *MyStruct `json:"data,omitempty"` Status string `json:"status,omitempty"` Reason string `json:"reason,omitempty"` }) err := json.Unmarshal(b, decoded) if err == nil { r.Data = decoded.Data r.Status = decoded.Status r.Reason = decoded.Reason } return err }
Si tiene estructuras enormes con muchos campos, esto puede volverse tedioso, especialmente cambiar la implementación de una estructura más adelante, pero a menos que vuelva a escribir todo el
json
paquete para satisfacer sus necesidades (no es una buena idea), esta es prácticamente la única forma en que puedo pensar en obtener esto se hace mientras se mantiene un no punteroMyStruct
allí.Además, no tiene que usar estructuras en línea, puede crear estructuras con nombre. Sin embargo, uso LiteIDE con finalización de código, por lo que prefiero en línea para evitar el desorden.
fuente
Data
es una estructura inicializada, por lo que no se considera vacía porqueencoding/json
solo mira el valor inmediato, no los campos dentro de la estructura.Desafortunadamente, regresar
nil
dejson.Marhsler
actualmente no funciona:func (_ MyStruct) MarshalJSON() ([]byte, error) { if empty { return nil, nil // unexpected end of JSON input } // ... }
También podrías dar
Result
un asesor, pero no vale la pena el esfuerzo.La única opción, como sugiere Matt, es hacer
Data
un puntero y establecer el valor ennil
.fuente
encoding/json
no puedo verificar los campos secundarios de la estructura. No sería muy eficiente, sí. Pero ciertamente no es imposible.json.Marshaler
embargo, se puede hacer caso por caso.MyStruct
está vacío mediante la implementación de unjson.Marshaler
sobreMyStruct
sí mismo. Prueba: play.golang.org/p/UEC8A3JGvxjson.Marshaler
en elResult
tipo contenedor en sí, lo que podría ser muy inconveniente.Existe una excelente propuesta de Golang para esta función que ha estado activa durante más de 4 años, por lo que en este punto, es seguro asumir que no se incluirá en la biblioteca estándar en el corto plazo. Como señaló @Matt, el enfoque tradicional es convertir las estructuras en punteros a estructuras . Si este enfoque no es factible (o impráctico), entonces una alternativa es usar un codificador json alternativo que admita la omisión de estructuras de valor cero .
Creé un espejo de la biblioteca Golang json ( clarketm / json ) con soporte adicional para omitir estructuras de valor cero cuando
omitempty
se aplica la etiqueta. Esta biblioteca detecta zeroness de manera similar al popular codificador YAML go-yaml al verificar de forma recursiva los campos de estructura públicos .p.ej
$ go get -u "github.com/clarketm/json"
import ( "fmt" "github.com/clarketm/json" // drop-in replacement for `encoding/json` ) type Result struct { Data MyStruct `json:"data,omitempty"` Status string `json:"status,omitempty"` Reason string `json:"reason,omitempty"` } j, _ := json.Marshal(&Result{ Status: "204", Reason: "No Content", }) fmt.Println(string(j))
// Note: `data` is omitted from the resultant json. { "status": "204" "reason": "No Content" }
fuente