jackson-databind
jackson-databind copied to clipboard
Cannot use both JsonCreator.Mode.DELEGATING and JsonCreator.Mode.PROPERTIES static creator factory methods in Enum, but can for Class
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.