SomethingSomething
SomethingSomething

Reputation: 12266

Jackson: Serialize and deserialize enum values as integers

Consider the following enum and class:

public enum State {
    OFF,
    ON,
    UNKNOWN
}

public class Machine {
    String name;
    int numCores;
    State state;

    public Machine(String name, int numCores, State state) {
        this.name = name;
        this.numCores = numCores;
        this.state = state;
    }
}

And consider the following main function:

public static void main(String args[]) {
    Machine m = new Machine("Machine 1", 8, State.OFF);
    ObjectMapper mapper = new ObjectMapper();
    String machineAsJsonString = mapper.writeValueAsString(m);
    System.out.println(machineAsJsonString);
}

Currently, the output of this main is:

{"name" : "Machine 1", "numCores" : 8, "state" : "OFF"}

This output is not good for me, as instead of the string "OFF" for state, I would like it to be 0, which is the ordinal value of OFF in the enum State.

So the actual result I want to get is:

{"name" : "Machine 1", "numCores" : 8, "state" : 0}

Is there some elegant way to make it behave this way?

Upvotes: 55

Views: 63629

Answers (8)

Jüri Raidma
Jüri Raidma

Reputation: 1

I had autogenerated enum classes, and could not add @JsonValue (or @XmlValue). I resolved this with custom serialize method, where I added:

objectMapper.enable(SerializationFeature.WRITE_ENUMS_USING_TO_STRING);

Complete method was like this, for example:

private static ObjectMapper createXmlMapper() {
  ObjectMapper objectMapper = new XmlMapper();
  objectMapper.registerModule(new JaxbAnnotationModule());
  JacksonXmlModule xmlModule = new JacksonXmlModule();
  xmlModule.setDefaultUseWrapper(false);
  objectMapper.registerModule(xmlModule);
  objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
  objectMapper.enable(SerializationFeature.WRITE_ENUMS_USING_TO_STRING);  // to overcome jackson enum serialization issue, where enum name is returned instead of value
  objectMapper.registerModule(new JavaTimeModule());
  return objectMapper;
}

// Method to serialize object to XML using XmlMapper
public static String serializeToXml(Object object) throws JsonProcessingException {
  ObjectMapper objectMapper = createXmlMapper();
  return objectMapper.writeValueAsString(object);
}

Upvotes: 0

Udayaditya Barua
Udayaditya Barua

Reputation: 1162

For integer enums, in kotlin, this works well. In java as well. If you don't want to use ordinals.

enum class State(@get:JsonValue val state: Int) {
          OFF(0),
          ON(1),
          UNKNOWN(-1)
}

Byte code generated is:

@JsonValue
public final int getState() {
  return this.state;

}

Upvotes: 0

Tom C
Tom C

Reputation: 814

If you want to print the ordinal of the enum you can change your constructor to accept an int instead of State and then in your call to Machine you can structure it in the following way:

Machine m = new Machine("Machine 1", 8, State.OFF.ordinal());

This will get the enum ordinal value of the passed in state and print the following

{name='Machine 1', numCores=8, state=0}

Upvotes: 2

Nikolai  Shevchenko
Nikolai Shevchenko

Reputation: 7521

Yet another way:

public enum State {

    @JsonProperty("0")
    OFF,

    @JsonProperty("1")
    ON,

    @JsonProperty("2")
    UNKNOWN
}

However, this will produce {"state" : "1"} instead of {"state" : 1} (string, not numeric). In most cases it's OK

Upvotes: 6

dasunse
dasunse

Reputation: 3099

You can use in this way

import com.fasterxml.jackson.annotation.JsonFormat;

@JsonFormat(shape = JsonFormat.Shape.NUMBER)
public enum State {
       OFF,
       ON,
       UNKNOWN
}

Upvotes: 17

user861594
user861594

Reputation: 5908

It should work by specifying JsonValue mapper.

public enum State {
    OFF,
    ON,
    UNKNOWN;

    @JsonValue
    public int toValue() {
        return ordinal();
    }
}  

This works for deserialization also, as noted in Javadoc of @JsonValue annotation:

NOTE: when use for Java enums, one additional feature is that value returned by annotated method is also considered to be the value to deserialize from, not just JSON String to serialize as. This is possible since set of Enum values is constant and it is possible to define mapping, but can not be done in general for POJO types; as such, this is not used for POJO deserialization

Upvotes: 94

Martin
Martin

Reputation: 1435

You can use setting

objectMapper.enable(SerializationFeature.WRITE_ENUMS_USING_INDEX);

See https://github.com/FasterXML/jackson-databind/blob/master/src/test/java/com/fasterxml/jackson/databind/ser/TestEnumSerialization.java for complete test cases

Thanks to tip at https://righele.it/2016/01/30/jackson-deserialization-from-json-to-java-enums/

Upvotes: 28

Paco Abato
Paco Abato

Reputation: 4065

For completion I post another way: custom serializer:

public class StateSerializer extends JsonSerializer<State> {  
    public void serialize(State value, JsonGenerator generator, SerializerProvider provider) throws IOException, JsonProcessingException {
        generator.writeStartObject();
        generator.writeFieldName("id");
        generator.writeNumber(value.getId());
        generator.writeEndObject();
    }
}

@JsonSerialize(using = StateSerializer.class)
public enum State { 
    ...
    public int getId(){...}
}

Upvotes: 5

Related Questions