For a project I'm working on I have to implement a struct for serde to deserialize some JSON data into. The other guys on the project have expressed their great desire that a certain field of the struct be an enum.
Unfortunately, it turns out that one of the possible values in the JSON includes a “-” character. Insofar as I have been able to determine, enum variants can't have dashes in their names.
How do I deserialize data that might contain dashes? I tried looking through the serde documentation, but haven't been able to find anything.
Here's an example of the kind of data I'm talking about:
{
"fubar": "foo-bar"
}
Use #[serde(rename)]:
enum Foo {
#[serde(rename = "foo-bar")]
FooBar,
}
Related
I'm writing a library to deserialize a subset of JSON into predefined Python types.
I want to deserialize arbitrary JSON into an object that quacks like serde-json's Value. However, I don't want it to deserialize into String's, Number's and Bool's - instead when the deserializer hits one of these I would prefer it simply keeps a reference to the respective byte string so I can efficiently (i.e. without the additional type conversion) parse the byte strings into the correct arbitrary Python types. Something like this:
use serde::Deserialize;
use serde_json::value::RawValue;
use serde_json::Map;
#[derive(Deserialize)]
pub enum MyValue<'a> {
Null,
Bytes(&'a RawValue),
Array(Vec<MyValue<'a>>),
Object(Map<String, MyValue<'a>>),
}
This will require writing a lot of traits so that it behaves like Value, and I'm not even sure if it won't just ignore deserializing the structural parts and put everything into a RawValue.
What is the cleanest way to do this?
I have a hard time deserializing (using Rust's serde and serde_json v1.0) the following JSON I receive:
{
["string content"]
}
The object's array is not identified by a key, so the following doesn't work:
#[derive(Deserialize)]
struct Data {
key: Vec<String>
}
I've also tried using #[serde(flatten)] on the key field but I get an error:
can only flatten structs and maps (got a sequence)
The data I receive doesn't look like valid JSON. Is it still possible using serde_json?
The input you show is not valid JSON. You will not be able to use serde_json to deserialize that input because serde_json only accepts JSON.
If you find out what format the data is intended to be in, consider using (or writing) a Rust library dedicated to that specific format.
I'm new to Go. I was trying to fetch and marshal json data to a struct. My sample data looks like this:
var reducedFieldData = []byte(`[
{"model":"Traverse","vin":"1gnkrhkd6ej111234"}
,{"model":"TL","vin":"19uua66265a041234"}
]`)
If I define the struct for receiving the data like this:
type Vehicle struct {
Model string
Vin string
}
The call to Unmarshal works as expected. However, if I use lower case for the fields ("model" and "vin") which actually matches cases for the field names in the data it will return empty strings for the values.
Is this expected behavior? Can the convention be turned off?
Fields need to be exported (declared with an uppercase first letter) or the reflection library cannot edit them. Since the JSON (un)marshaller uses reflection, it cannot read or write unexported fields.
So yes, it is expected, and no, you cannot change it. Sorry.
You can add tags to a field to change the name the marshaller uses:
Model string `json:"model"`
See the documentation for more info on the field tags "encoding/json" supports.
I am working with an API that, frustratingly, has field names that vary for the same value. For example, one API response could look like this:
{
"PersonFirstName": "John",
"PersonLastName": "Smith"
}
while another looks like this:
{
"FirstNm": "John",
"LastNm": "Smith"
}
Suppose then I had a struct which I would like to decode my JSON to. It might look like this:
type Name struct {
FirstName string
LastName string
}
Typically I would just be able to do the following if the API was consistent:
type Name struct {
FirstName string `json:"PersonFirstName"`
LastName string `json:"PersonLastName"`
}
and then use the built-in JSON decoder to build the struct. When there are multiple field values like this, though, I don't know a clean way to decode the JSON into a struct. Any ideas?
Use a map[string]string. That is the equivalent structure in Go. You're looking at those as being structs because their objects, and that's the sensible thing to do. Anytime you see different values for the property names that's your clue that a map is the only reasonable representation of the data in Go.
If you need to normalize/have static typing implement a helper function called NameFromMap(data map[string]string) (*Name, error). Put the switch statement in there to deal with the various values you can have for the keys.
Edit: you could also implement UnmarshalJSON for your type. You would just put this switch statement I allude to there. Here's an example; How do I Unmarshal JSON?
I personally prefer the first method I said because this sort of abstracts a step that I'd rather see called explicitly.
I have some big json files that are slightly different in the types that the fields contain.
{ "a":"1" }
vs.
{ "a":1 }
When I unmarshal the second I get:
cannot unmarshal number into Go value of type string
However since these jsons are large I would like to have the actual field that is in error so I can fix them. The UnmarshalTypeError does not hold the Struct's field type.
Does anybody know of a way to get to field name? (not debugging I have a lot of different fields that err)
[EDIT]
I know how to solve the type conversion. What I need is a method to see what fields I need to apply that conversion to.
The short answer is that you can't.
However, to fix your problem, there is multiple solutions:
Dive into the json.Unmarshal source code to change its working and add the information you need: copy the function to a local package, do your edits, and use this function
Use a thrid-party tool to help you, for example a JSON validator compatible with JSON Schema: here is an online example, there is probably some better-suited tool
Now the UnmarshalTypeError, contains the field name.