Ryan Morrison
Ryan Morrison

Reputation: 593

Jackson: Deserializing enums

I'm using Jackson + Spring in a REST API. One of the API calls has JSON that looks like this:

{
    "status": "Suspended"
}

where the value of "status" is mapped to a Java enum, like so:

public enum FeatureStatus {
    Activated(0),
    Inactivated(1),
    Suspended(2),
    Deleted(3);

    private FeatureStatus(int id) {
        this.id = id;
    }

    private int id;

    public int getId() {
        return id;
    }

    public FeatureStatus valueOf(int id) {
        switch(id) {
            case 1: return Inactivated;
            case 2: return Suspended;
            case 3: return Deleted;
            default: return Activated;
        }
    }

    @JsonCreator
    public static FeatureStatus fromValue(String status) {
        if(status != null) {
            for(FeatureStatus featureStatus : FeatureStatus.values()) {
                if(featureStatus.toString().equals(status)) {
                    return featureStatus;
                }
            }

            throw new IllegalArgumentException(status + " is an invalid value.");
        }

        throw new IllegalArgumentException("A value was not provided.");
    }
}

However, this exception gets thrown: java.lang.IllegalArgumentException: { is an invalid value. It looks like it's not deserializing the JSON at all. My controller method has this definition:

public @ResponseBody void updateFeatureStatusById(@PathVariable long featureId, @RequestBody FeatureStatus updated) {

Any other controller automatically deserializes the JSON fine as expected using this format. How can I deserialize this JSON into my enum?

Upvotes: 1

Views: 5568

Answers (2)

StaxMan
StaxMan

Reputation: 116610

Is the exact JSON you pass an Object? Enums except either JSON String or number, not Object. If you need to give an object, you should map it to something like:

public class EnumWrapper {
  public FeatureStatus status;
}

and it'll work.

Upvotes: 2

Jukka
Jukka

Reputation: 4663

Put this class next to your controller:

final class FeatureStatusJsonObject {
     public FeatureStatus status;
}

And then in the controller method use this:

@RequestBody FeatureStatusJsonObject updated

and get the real FeatureStatus by

updated.status

This makes the conversion from a JSON object to an Enum literal explicit in your code, and allows you to use the regular Enum <-> String (de)serialization elsewhere (if necessary).

On an unrelated note, this looks a bit funky:

@ResponseBody void

I would just make it void.

Upvotes: 4

Related Questions