Skip to content

Cannot use both JsonCreator.Mode.DELEGATING and JsonCreator.Mode.PROPERTIES static creator factory methods for Enums #3566

@andrewbents

Description

@andrewbents

Describe the bug
When Enum has two factory methods, one with JsonCreator.Mode.DELEGATING and the other with JsonCreator.Mode.PROPERTIES, only the latter works. Deserialization that is supposed to target the DELEGATING one fails with com.fasterxml.jackson.databind.exc.MismatchedInputException.
Note that the same setup for a POJO works just fine.

Version information
2.13.3

To Reproduce

class TestCases {
    @Test
    void testClass() throws JsonProcessingException {
        ObjectMapper objectMapper = new ObjectMapper();
        Assertions.assertEquals(new AClass("someName"), objectMapper.readValue("{ \"name\": \"someName\" }", AClass.class));
        Assertions.assertEquals(new AClass("someName"), objectMapper.readValue("\"someName\"", AClass.class));
    }

    @Test
    void testEnum() throws JsonProcessingException {
        ObjectMapper objectMapper = new ObjectMapper();
        Assertions.assertEquals(AEnum.A, objectMapper.readValue("{ \"type\": \"AType\" }", AEnum.class));
        Assertions.assertEquals(AEnum.A, objectMapper.readValue("\"AType\"", AEnum.class)); // this line fails
    }
}

class AClass {
    private final String name;

    AClass(String name) {
        this.name = name;
    }

    public String getName() {
        return name;
    }

    @JsonCreator(mode = JsonCreator.Mode.DELEGATING)
    public static AClass fromString(String name) {
        return new AClass(name);
    }

    @JsonCreator(mode = JsonCreator.Mode.PROPERTIES)
    public static AClass create(@JsonProperty("name") String name) {
        return new AClass(name);
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        AClass aClass = (AClass) o;
        return Objects.equals(name, aClass.name);
    }

    @Override
    public int hashCode() {
        return Objects.hash(name);
    }
}

@JsonFormat(shape = JsonFormat.Shape.OBJECT)
enum AEnum {
    A("AType"),
    B("BType");

    private final String type;

    AEnum(String type) {
        this.type = type;
    }

    public String getType() {
        return type;
    }

    @JsonCreator(mode = JsonCreator.Mode.DELEGATING)
    public static AEnum fromString(String type) {
        return Arrays.stream(values())
                .filter(aEnum -> aEnum.type.equals(type))
                .findFirst()
                .orElseThrow();
    }

    @JsonCreator(mode = JsonCreator.Mode.PROPERTIES)
    public static AEnum create(@JsonProperty("type") String type) {
        return fromString(type);
    }
}

The testClass passes, but testEnum fails with

com.fasterxml.jackson.databind.exc.MismatchedInputException: Input mismatch reading Enum `AEnum`: properties-based `@JsonCreator` ([method AEnum#fromString(java.lang.String)]) expects JSON Object (JsonToken.START_OBJECT), got JsonToken.VALUE_STRING

Also, you can remove the PROPERTIES factory method, and the DELEGATING method would work.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enumRelated to handling of Enum values

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions