Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Deserializing an enum with Jackson

Tags:

java

json

jackson

I'm trying and failing to deserialize an enum with Jackson 2.5.4, and I don't quite see my case out there. My input strings are camel case, and I want to simply map to standard Enum conventions.

@JsonFormat(shape = JsonFormat.Shape.STRING) public enum Status {     READY("ready"),     NOT_READY("notReady"),     NOT_READY_AT_ALL("notReadyAtAll");      private static Map<String, Status> FORMAT_MAP = Stream             .of(Status.values())             .collect(toMap(s -> s.formatted, Function.<Status>identity()));      private final String formatted;      Status(String formatted) {         this.formatted = formatted;     }      @JsonCreator     public Status fromString(String string) {         Status status = FORMAT_MAP.get(string);         if (status == null) {             throw new IllegalArgumentException(string + " has no corresponding value");         }         return status;     } } 

I've also tried @JsonValue on a getter to no avail, which was an option I saw reported elsewhere. They all blow up with:

com.fasterxml.jackson.databind.exc.InvalidFormatException: Can not construct instance of ...Status from String value 'ready': value not one of declared Enum instance names: ... 

What am I doing wrong?

like image 377
jwilner Avatar asked Jul 29 '15 00:07

jwilner


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.

Can enum implement serializable?

Because enums are automatically Serializable (see Javadoc API documentation for Enum), there is no need to explicitly add the "implements Serializable" clause following the enum declaration.

Can enum be subclassed?

We've learned that we can't create a subclass of an existing enum. However, an interface is extensible. Therefore, we can emulate extensible enums by implementing an interface.


1 Answers

EDIT: Starting from Jackson 2.6, you can use @JsonProperty on each element of the enum to specify its serialization/deserialization value (see here):

public enum Status {     @JsonProperty("ready")     READY,     @JsonProperty("notReady")     NOT_READY,     @JsonProperty("notReadyAtAll")     NOT_READY_AT_ALL; } 

(The rest of this answer is still valid for older versions of Jackson)

You should use @JsonCreator to annotate a static method that receives a String argument. That's what Jackson calls a factory method:

public enum Status {     READY("ready"),     NOT_READY("notReady"),     NOT_READY_AT_ALL("notReadyAtAll");      private static Map<String, Status> FORMAT_MAP = Stream         .of(Status.values())         .collect(Collectors.toMap(s -> s.formatted, Function.identity()));      private final String formatted;      Status(String formatted) {         this.formatted = formatted;     }      @JsonCreator // This is the factory method and must be static     public static Status fromString(String string) {         return Optional             .ofNullable(FORMAT_MAP.get(string))             .orElseThrow(() -> new IllegalArgumentException(string));     } } 

This is the test:

ObjectMapper mapper = new ObjectMapper();  Status s1 = mapper.readValue("\"ready\"", Status.class); Status s2 = mapper.readValue("\"notReadyAtAll\"", Status.class);  System.out.println(s1); // READY System.out.println(s2); // NOT_READY_AT_ALL 

As the factory method expects a String, you have to use JSON valid syntax for strings, which is to have the value quoted.

like image 173
fps Avatar answered Sep 27 '22 20:09

fps