handling - JSON y tratar con campos no exportados
json to interface golang (2)
¿Hay algún motivo técnico por el que los campos no exportados no estén incluidos en la codificación / json? De lo contrario, y se trata de una decisión arbitraria, ¿podría existir una opción de puerta trasera adicional (por ejemplo, "+") para incluir aunque no se haya exportado?
Exigir que el código del cliente se exporte para obtener esta funcionalidad se siente desafortunado, especialmente si la minúscula proporciona encapsulación o si la decisión de organizar las estructuras llega mucho más tarde que el diseño de las mismas.
¿Cómo están lidiando las personas con esto? Solo exportar todo?
Además, no exportar nombres de campo hace que sea difícil seguir los modismos sugeridos. Creo que si una estructura X tiene el campo Y, no puede tener un método de acceso Y (). Si desea proporcionar acceso a la interfaz a Y, tiene que encontrar un nuevo nombre para el comprador y no importa de qué obtendrá algo no idiomático de acuerdo con http://golang.org/doc/effective_go.html#Getters
Hay una razón técnica. La biblioteca json no tiene la capacidad de ver campos usando reflect a menos que se exporten. Un paquete solo puede ver los campos de tipos no exportados dentro de su propio paquete
Para resolver su problema, lo que puede hacer es crear un tipo no exportado con los campos exportados. Json se convertirá en un tipo no exportado si se le transfiere sin problemas, pero no se mostrará en los documentos de la API. Luego puede hacer un tipo exportado que incruste el tipo no exportado. Este tipo exportado necesitaría entonces métodos para implementar las interfaces json.Marshaler
y json.Unmarshaler
.
Nota: todos los códigos no han sido probados y es posible que ni siquiera compilen.
type jsonData struct {
Field1 string
Field2 string
}
type JsonData struct {
jsonData
}
// Implement json.Unmarshaller
func (d *JsonData) UnmarshalJSON(b []byte) error {
return json.Unmarshal(b, &d.jsonData)
}
// Getter
func (d *JsonData) Field1() string {
return d.jsonData.Field1
}
La respuesta de Stephen está completa. Como comentario adicional, si todo lo que realmente quieres son las teclas en minúscula en tu json, puedes especificar manualmente el nombre de la tecla de la siguiente manera:
type Whatever struct {
SomeField int `json:"some_field"`
}
De esa forma, ordenar un Lo que produce la clave "some_field" para el campo SomeField (en lugar de tener "SomeField" en tu json).
Si está decidido a mantener los campos no exportados, también puede implementar la interfaz json.Marshaler definiendo un método con la firma MarshalJSON() ([]byte, error)
. Una forma de hacerlo es utilizar una estructura literal que simplemente haya exportado versiones de los campos no exportados, como esta:
type Whatever struct {
someField int
}
func (w Whatever) MarshalJSON() ([]byte, error) {
return json.Marshal(struct{
SomeField int `json:"some_field"`
}{
SomeField: w.someField,
})
}
Eso puede ser un poco engorroso, por lo que también puede usar un map[string]interface{}
si lo prefiere:
func (w Whatever) MarshalJSON() ([]byte, error) {
return json.Marshal(map[string]interface{}{
"some_field": w.SomeField,
})
}
Sin embargo, debe tenerse en cuenta que la interface{}
uint64
de uint64
interface{}
tiene algunas advertencias y puede hacer cosas como uint64
a un flotador, lo que causa una pérdida de precisión. (todo el código no probado)