Search code examples
javajsonserializationenumsjackson

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));

Solution

  • 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();
        }
      }
    }