Say Goodbye to toString(): Multiple Ways to Handle Enums with Jackson in Spring Boot

This article compares four techniques—@JsonValue/@JsonCreator, @JsonFormat, custom serializers/deserializers, and a global @JsonComponent—to control how Java enums are serialized and deserialized by Jackson in Spring Boot, and outlines important pitfalls and version‑compatibility tips.

Senior Xiao Ying
Senior Xiao Ying
Senior Xiao Ying
Say Goodbye to toString(): Multiple Ways to Handle Enums with Jackson in Spring Boot

Using @JsonValue and @JsonCreator

This method defines code and desc fields inside the enum, annotates a @JsonValue getter to emit the code during serialization, and provides a static @JsonCreator method to locate the enum instance from the incoming value.

import com.fasterxml.jackson.annotation.JsonCreator;
import com.fasterxml.jackson.annotation.JsonValue;

public enum Status {
    EXAMPLE_1("example1", "示例一"),
    EXAMPLE_2("example2", "示例二");

    private final String code;
    private final String desc;

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

    @JsonValue
    public String getCode() {
        return code;
    }

    @JsonCreator
    public static Status fromCode(String code) {
        for (Status s : Status.values()) {
            if (s.code.equals(code)) {
                return s;
            }
        }
        throw new IllegalArgumentException("未知的状态码: " + code);
    }

    public String getDesc() {
        return desc;
    }
}

Serialization : Returning Status.EXAMPLE_1 from a controller produces the JSON string "example1".

Deserialization : A JSON payload {"status": "example1"} is automatically converted to Status.EXAMPLE_1 via fromCode.

Limitation : Only the code value is emitted; the desc field is omitted.

Serializing as a Complete JSON Object with @JsonFormat

When the client needs the full enum information, annotate the enum with @JsonFormat(shape = JsonFormat.Shape.OBJECT). The @JsonCreator method extracts the code from the incoming object.

import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonProperty;

@JsonFormat(shape = JsonFormat.Shape.OBJECT)
public enum DetailedStatus {
    @JsonProperty("example1")
    EXAMPLE_1("example1", "示例一"),
    @JsonProperty("example2")
    EXAMPLE_2("example2", "示例二");

    private final String code;
    private final String desc;

    DetailedStatus(String code, String desc) {
        this.code = code;
        this.desc = desc;
    }

    public String getCode() { return code; }
    public String getDesc() { return desc; }

    @JsonCreator
    public static DetailedStatus forObject(@JsonProperty("code") String code) {
        for (DetailedStatus s : DetailedStatus.values()) {
            if (s.code.equals(code)) {
                return s;
            }
        }
        throw new IllegalArgumentException("未知的状态码: " + code);
    }
}

Serialization : DetailedStatus.EXAMPLE_1 becomes {"code":"example1","desc":"示例一"}.

Deserialization : The client must send an object like {"code":"example1"}; Jackson invokes the @JsonCreator method to obtain the enum instance.

Custom Serializer and Deserializer

For complex logic or to apply uniform behavior across many enums, implement explicit serializer and deserializer classes.

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
import com.fasterxml.jackson.databind.SerializerProvider;
import java.io.IOException;

public class StatusEnumSerializer extends JsonSerializer<Status> {
    @Override
    public void serialize(Status value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
        // Write only the enum's code value.
        gen.writeString(value.getCode());
    }
}
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import java.io.IOException;

public class StatusEnumDeserializer extends JsonDeserializer<Status> {
    @Override
    public Status deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
        // Extract the text value from the JSON parser.
        String code = p.getText();
        // Reuse the enum's lookup method.
        return Status.fromCode(code);
    }
}

Apply them to the enum:

import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;

@JsonSerialize(using = StatusEnumSerializer.class)
@JsonDeserialize(using = StatusEnumDeserializer.class)
public enum Status {
    // enum definition identical to the method‑1 example
    EXAMPLE_1("example1", "示例一"),
    EXAMPLE_2("example2", "示例二");

    private final String code;
    private final String desc;

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

    public String getCode() { return code; }
    public String getDesc() { return desc; }

    public static Status fromCode(String code) {
        for (Status s : Status.values()) {
            if (s.code.equals(code)) {
                return s;
            }
        }
        throw new IllegalArgumentException("未知的状态码: " + code);
    }
}

Registering a Global Handler with @JsonComponent

If annotating each enum is undesirable, create a component annotated with @JsonComponent. Spring Boot automatically registers it as a Jackson module, providing serializer and deserializer for the target enum.

import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.core.JsonToken;
import com.fasterxml.jackson.databind.*;
import org.springframework.boot.jackson.JsonComponent;
import java.io.IOException;

@JsonComponent
public class StatusEnumJsonComponent {
    public static class StatusSerializer extends JsonSerializer<Status> {
        @Override
        public void serialize(Status value, JsonGenerator gen, SerializerProvider serializers) throws IOException {
            gen.writeString(value.getCode());
        }
    }

    public static class StatusDeserializer extends JsonDeserializer<Status> {
        @Override
        public Status deserialize(JsonParser p, DeserializationContext ctxt) throws IOException {
            if (p.getCurrentToken() == JsonToken.VALUE_STRING) {
                String code = p.getText().trim();
                if (code.isEmpty()) {
                    return null;
                }
                return Status.fromCode(code);
            }
            throw ctxt.mappingException("Expected JSON String for Status enum");
        }
    }
}

After this component is on the classpath, Jackson automatically uses the serializer and deserializer for any Status field without further annotations.

Important Reminders

Avoid Recursive Traps : Do not call toString() inside the enum's serialization logic, as it can cause infinite recursion and a StackOverflowError. Keep toString() lightweight.

Spring Boot 4.x and Jackson 3 : Spring Boot 4.0.0‑RC1 fully supports Jackson 3. Class names prefixed with Json have been renamed to Jackson, and JsonMapper is now preferred over ObjectMapper. The core annotations @JsonValue and @JsonCreator remain unchanged.

Version Compatibility : Verify that the Spring Boot version used is compatible with the Jackson version (2.x or 3.x). All techniques described work with Jackson 2.x and also with Jackson 3.x after the API name changes.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaEnumSpring BootjacksonJsonComponentJsonCreatorJsonValue
Senior Xiao Ying
Written by

Senior Xiao Ying

Dedicated to sharing Java backend technical experience and original tutorials, offering career transition advice and resume editing. Recognized as a rising star in CSDN's Java backend community and ranked Top 3 in the 2022 New Star Program for Java backend.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.