Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Jackson databind enum case insensitive

How can I deserialize JSON string that contains enum values that are case insensitive? (using Jackson Databind)

The JSON string:

[{"url": "foo", "type": "json"}]

and my Java POJO:

public static class Endpoint {

    public enum DataType {
        JSON, HTML
    }

    public String url;
    public DataType type;

    public Endpoint() {

    }

}

in this case,deserializing the JSON with "type":"json" would fail where as "type":"JSON" would work. But I want "json" to work as well for naming convention reasons.

Serializing the POJO also results in upper case "type":"JSON"

I thought of using @JsonCreator and @JsonGetter:

    @JsonCreator
    private Endpoint(@JsonProperty("name") String url, @JsonProperty("type") String type) {
        this.url = url;
        this.type = DataType.valueOf(type.toUpperCase());
    }

    //....
    @JsonGetter
    private String getType() {
        return type.name().toLowerCase();
    }

And it worked. But I was wondering whether there's a better solutuon because this looks like a hack to me.

I can also write a custom deserializer but I got many different POJOs that use enums and it would be hard to maintain.

Can anyone suggest a better way to serialize and deserialize enums with proper naming convention?

I don't want my enums in java to be lowercase!

Here is some test code that I used:

    String data = "[{\"url\":\"foo\", \"type\":\"json\"}]";
    Endpoint[] arr = new ObjectMapper().readValue(data, Endpoint[].class);
        System.out.println("POJO[]->" + Arrays.toString(arr));
        System.out.println("JSON ->" + new ObjectMapper().writeValueAsString(arr));
like image 936
tom91136 Avatar asked Jun 11 '14 08:06

tom91136


People also ask

Is Jackson case sensitive?

Jackson is a well-known library for JSON utilities. It has a wide area of features. One of them is case insensitive deserialization for field names.

Is enum value of case sensitive?

I'm also a fan of simple things – and believe it's simpler in implementation to say enum values are case-insensitive, that implementations will always naturally produce values in uppercase, than it is to special-case handling in all languages that the deserialized values are uppercase, and may fill an UNKNOWN value.

How does Jackson handle enums?

By default, Jackson will use the Enum name to deserialize from JSON. If we want Jackson to case-insensitively deserialize from JSON by the Enum name, we need to customize the ObjectMapper to enable the ACCEPT_CASE_INSENSITIVE_ENUMS feature.


2 Answers

Jackson 2.9

This is now very simple, using jackson-databind 2.9.0 and above

ObjectMapper objectMapper = new ObjectMapper();
objectMapper.enable(MapperFeature.ACCEPT_CASE_INSENSITIVE_ENUMS);

// objectMapper now deserializes enums in a case-insensitive manner

Full example with tests

import com.fasterxml.jackson.databind.MapperFeature;
import com.fasterxml.jackson.databind.ObjectMapper;

public class Main {

  private enum TestEnum { ONE }
  private static class TestObject { public TestEnum testEnum; }

  public static void main (String[] args) {
    ObjectMapper objectMapper = new ObjectMapper();
    objectMapper.enable(MapperFeature.ACCEPT_CASE_INSENSITIVE_ENUMS);

    try {
      TestObject uppercase = 
        objectMapper.readValue("{ \"testEnum\": \"ONE\" }", TestObject.class);
      TestObject lowercase = 
        objectMapper.readValue("{ \"testEnum\": \"one\" }", TestObject.class);
      TestObject mixedcase = 
        objectMapper.readValue("{ \"testEnum\": \"oNe\" }", TestObject.class);

      if (uppercase.testEnum != TestEnum.ONE) throw new Exception("cannot deserialize uppercase value");
      if (lowercase.testEnum != TestEnum.ONE) throw new Exception("cannot deserialize lowercase value");
      if (mixedcase.testEnum != TestEnum.ONE) throw new Exception("cannot deserialize mixedcase value");

      System.out.println("Success: all deserializations worked");
    } catch (Exception e) {
      e.printStackTrace();
    }
  }
}
like image 161
davnicwil Avatar answered Sep 22 '22 15:09

davnicwil


I ran into this same issue in my project, we decided to build our enums with a string key and use @JsonValue and a static constructor for serialization and deserialization respectively.

public enum DataType {
    JSON("json"), 
    HTML("html");

    private String key;

    DataType(String key) {
        this.key = key;
    }

    @JsonCreator
    public static DataType fromString(String key) {
        return key == null
                ? null
                : DataType.valueOf(key.toUpperCase());
    }

    @JsonValue
    public String getKey() {
        return key;
    }
}
like image 38
Sam Berry Avatar answered Sep 21 '22 15:09

Sam Berry