I just released Module 10 in the Master Class of my "REST With Spring" Course:

>> THE "REST WITH SPRING" CLASSES

1. Overview

This quick tutorial will show how to control the way Java Enums are serialized to JSON output with Jackson 2.

If you want to dig deeper and learn other cool things you can do with the Jackson 2 – head on over to the main Jackson tutorial.

Further reading:

Jackson – Custom Serializer

Control your JSON output with Jackson 2 by using a Custom Serializer.

Read more

XML Serialization and Deserialization with Jackson

This short tutorial shows how the Jackson library can be used to serialize Java object to XML and deserialize them back to objects.

Read more

Jackson – Decide What Fields Get Serialized/Deserialized

How to control which fields get serialized/deserialized by Jackson and which fields get ignored.

Read more

2. Controlling the Enum Representation

Let’s define the following Enum:

public enum Distance {
    KILOMETER("km", 1000), 
    MILE("miles", 1609.34),
    METER("meters", 1), 
    INCH("inches", 0.0254),
    CENTIMETER("cm", 0.01), 
    MILLIMETER("mm", 0.001);

    private String unit;
    private final double meters;

    private Distance(String unit, double meters) {
        this.unit = unit;
        this.meters = meters;
    }

    // standard getters and setters
}

3. Default Enum Representation

By default, Jackson will represent Java Enums as simple String – for example:

new ObjectMapper().writeValueAsString(Distance.MILE);

Will result in:

"MILE"

What we would like to get when marshaling this ENUM to a JSON Object is to give something like:

{"unit":"miles","meters":1609.34}

4. Enum as Json Object

Starting with Jackson 2.1.2 – the is now a configuration option that can handle this kind of representation – via the @JsonFormat annotation, at the Enum level:

@JsonFormat(shape = JsonFormat.Shape.OBJECT)
public enum Distance { ... }

This will lead to the correct result when serializing this enum for Distance.MILE:

{"unit":"miles","meters":1609.34}

5. Enums and @JsonValue

Yet another simple way of controlling the marshaling output for an enum is using the @JsonValue annotation on a getter:

public enum Distance { 
    ...
 
    @JsonValue
    public String getMeters() {
        return meters;
    }
}

What we’re saying here is that getMeters() is the actual representation of this enum. So the result of serializing:

1609.34

6. Custom Serializer for Enum

Before Jackson 2.1.2, or if even more customization is required for the enum – we can use a custom Jackson serializer – first we’ll need to define it:

public class DistanceSerializer extends StdSerializer {
    
    public DistanceSerializer() {
        super(Distance.class);
    }

    public DistanceSerializer(Class t) {
        super(t);
    }

    public void serialize(Distance distance, JsonGenerator generator,
      SerializerProvider provider) 
      throws IOException, JsonProcessingException {
        generator.writeStartObject();
        generator.writeFieldName("name");
        generator.writeNumber(distance.name());
        generator.writeFieldName("unit");
        generator.writeString(distance.getUnit());
        generator.writeFieldName("meters");
        generator.writeNumber(distance.getMeters());
        generator.writeEndObject();
    }
}

We will now tie together the serializer and the class it applies to:

@JsonSerialize(using = DistanceSerializer.class)
public enum TypeEnum { ... }

The result:

{"name":MILE,"unit":"miles","meters":1609.34}

7. Conclusion

This article illustrated how to gain better control over the serialization process and format of Java Enums.

The implementation of all these examples and code snippets can be found over on Github – this is an Eclipse based project, so it should be easy to import and run as it is.

I just released Module 10 in the Master Class of my "REST With Spring" Course:

>> THE "REST WITH SPRING" CLASSES

  • TatuSaloranta

    Good stuff. Two more suggestions for things to include: @JsonValue (serialize enum using value a method returns — yes, you can define custom methods for enum), and @JsonCreator for indicating factory method (that takes a single String arg) to use for reading Enums back.

    • Hey Tatu – I was looking into using @JsonValue, but it looks like it’s not yet implemented: https://github.com/FasterXML/jackson-databind/issues/47
      Let me know if your own experience is different with this one. Cheers,
      Eugen.

      • TatuSaloranta

        Well yes and no: yes, it is implemented for regular values; but no, not
        when using Enums as keys of EnumMap (or Map).

        • Sounds good Tatu – I updated the article – thanks for the heads up. Cheers,
          Eugen.

  • Is there also a short form that uses Enum.name() and Enum.ordinal() as default implementations? I.e. that way, you don’t have to explicitly write the serialisation code…

    • Hey Lukas. Yes – the default behaviour of Jackson does uses name() – so, if the name of the enum is enough, you don’t need to do anything else. In my examples, the name wasn’t enough because the enum also had an id.
      Even so – you don’t need to write custom serialization – @JsonFormat would be enough.
      The custom serializer is only for very specific requirements, where the standard object representation you would get from @JsonFormat isn’t enough either.
      Hope that clarifies things. Cheers,
      Eugen.

  • von

    Please write about Jackson & GSON, which one should i use ?

    • Without more context, I’m going to give you my personal preference – and that’s Jackson.

  • Kasim

    Hi,
    thank you very much for your helpful posts. But wouldn’t it be better to register the serializer to the object mapper. In this way you don’t need to write any jackson annotations within your domain model.
    Regards,
    Dino

    • Hey Kasim – sure, a serializer is an option (see Section 6) – but it’s lower level so sometimes it’s easier to go with an annotation.