Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I deserialize an enum when the case doesn't match?

I have a JSON structure that looks like this:

{ "type": "suite", "event": "started", "test_count": 1 }

I want to deserialize into these structs:

#[derive(Debug, Deserialize)]
enum ResultType {
    Suite,
    Test,
}

#[derive(Debug, Deserialize)]
enum ResultEvent {
    Started,
    Failed,
    Ok,
}

#[derive(Debug, Deserialize)]
struct JsonResult {
    #[serde(rename(deserialize = "type"))]
    test_type: ResultType,
    event: ResultEvent,
    test_count: Option<u32>,
}

I can't find a way to make serde_json use the correct case. I keep getting these errors:

Error("unknown variant `suite`, expected `Suite` or `Test`", line: 1, column: 17)

If I change the case of the enum values to all lowercase or all uppercase it works, but I'd like to be able to use PascalCase.

like image 267
CaseyB Avatar asked Dec 04 '19 00:12

CaseyB


People also ask

How does Jackson deserialize enum?

Deserializing JSON String to Enum Using @JsonValue Annotation. The @JsonValue annotation is one of the annotations which we can use for both serializing and deserializing enums. Enum values are constants, and due to this, @JsonValue annotation can be used for both. First we simply add the getter method to our Distance.

How do you serialize an enum?

To serialize an enum constant, ObjectOutputStream writes the value returned by the enum constant's name method. To deserialize an enum constant, ObjectInputStream reads the constant name from the stream; the deserialized constant is then obtained by calling the java.


3 Answers

You just need to put #[serde(rename_all = "snake_case")] before the enum definition.

Other possible values are lowercase, UPPERCASE, PascalCase, camelCase, snake_case, SCREAMING_SNAKE_CASE, kebab-case, and SCREAMING-KEBAB-CASE.

like image 159
Coder-256 Avatar answered Jan 04 '23 12:01

Coder-256


Use #[serde(rename = "name")] to change the string used for the enum variant when serializing and deserializing.

#[derive(Debug, Deserialize)]
enum ResultType {
    #[serde(rename = "suite")]
    Suite,
    #[serde(rename = "test")]
    Test,
}

#[derive(Debug, Deserialize)]
enum ResultEvent {
    #[serde(rename = "started")]
    Started,
    #[serde(rename = "failed")]
    Failed,
    #[serde(rename = "ok")]
    Ok,
}

#[derive(Debug, Deserialize)]
struct JsonResult {
    #[serde(rename(deserialize = "type"))]
    test_type: ResultType,
    event: ResultEvent,
    test_count: Option<u32>,
}

You can also use #[serde(alias = "name")] to add an extra string to accept when deserializing.

Details are in the serde documentation: https://serde.rs/variant-attrs.html

like image 29
M. Leonhard Avatar answered Jan 04 '23 11:01

M. Leonhard


I think the tricker is using

#[serde(alias="Field", alias="filed", alias="FIELD")]

at the fields.

Because I think "Field" and "field" and "FIELD" is acceptable.

And any other case like "fIelD", there must be something wrong.

like image 41
govo Avatar answered Jan 04 '23 12:01

govo