Jackson – deserialization of Integer to Enum

Problem Statement: I work in a Restful micro-service which is kind of a delegator or an orchestrator API on top of many other micro-services. Majority of the application logic lies in mapper classes that maps requests and responses to and from different dependent APIs. Having a clean and readable set of POJOs is a pre-requisite to have a clean, readable and maintainable set of mapper classes.

There are many instances wherein I had to de-serialize certain values coming from the dependent APIs to a Java enum. Normally when I want to deserialize a string, I use @JsonProperty annotation in my enum values to get it de-serialized to the enum.

For example, consider the below JSON payload which is a list of products. For some good reason, I had to declare productType as a enum in my POJO class. And Jackson’s @JsonProperty annotation helps me to de-serialize it.

[
  {
    "productName": "Savings",
    "productType": "PT01"
  },
  {
    "productName": "Loans",
    "productType": "PT02"
  }
]

Here is my POJO for an individual Product

@Data
public class Product {
    private String productName;
    private ProductType product;
}

@Getter
enum ProductType {
    @JsonProperty("PT01")
    PT01("PT01", "This is a savings product"),
    @JsonProperty("PT02")
    PT02("PT02", "This is a loans product"),
    @JsonEnumDefaultValue
    UNKNOWN("XX00", "This is a unknown product");
    private String code;
    private String description;

    ProductType(String code, String description) {
        this.code = code;
        this.description = description;
    }
}

But unfortunately, the above solution will only work when the incoming json value is a string. It won’t for integers and other data types.

For example, consider the below JSON payload

{
  "name": "NoName",
  "status": 101
}

The previous solution with @JsonProperty annotation will not work in this case because the data type of status is an integer.

Solution: I had to write a factory method with @JsonCreator annotation to fix this. And eere is my solution. If there are better alternatives, please feel free to add it in the comments.

@Data
class JsonPayload {
    private String name;
    private Status status;
}

enum Status {
    CODE_101(101, "OK"),
    CODE_102(102, "NOK"),
    UNKNOWN(-1, "UNKNOWN");

    private int code;
    private String value;

    Status(int code, String value) {
        this.code = code;
        this.value = value;
    }

    @JsonCreator
    public static Status fromCode(Integer code){
        return stream(values()).filter(e -> e.code == code)
            .findFirst()
            .orElse(UNKNOWN);
    }

}

Here I have a factory method fromCode that iterates through all the values and returns the appropriate enum. The @JsonCreator annotation is a marker annotation that helps Jackson to identify the factory method to be used for instantiating the status object.

@JsonCreator
public static Status fromCode(Integer code){
   return stream(values()).filter(e -> e.code == code)
            .findFirst()
            .orElse(UNKNOWN);
}

Checkout my github for my complete code. If there are better ways to do it, please comment it out in the comments section.

Leave a Comment