EnumDeserNumberJsonProperty5330Test.java
package tools.jackson.databind.deser.enums;
import java.util.*;
import org.junit.jupiter.api.Test;
import com.fasterxml.jackson.annotation.JsonFormat;
import com.fasterxml.jackson.annotation.JsonProperty;
import tools.jackson.databind.*;
import tools.jackson.databind.cfg.EnumFeature;
import tools.jackson.databind.exc.MismatchedInputException;
import tools.jackson.databind.testutil.DatabindTestUtil;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertThrows;
/**
* [databind#5330] Deserialization: {@code @JsonProperty} value used as numeric index
* for Enums with {@code Shape.NUMBER}
*/
public class EnumDeserNumberJsonProperty5330Test extends DatabindTestUtil
{
// no JsonFormat override: used to verify that numeric @JsonProperty is NOT used as index.
public enum MyEnumNoFormat {
@JsonProperty("7")
FOO,
@JsonProperty("42")
BAR
}
@JsonFormat(shape = JsonFormat.Shape.NUMBER)
public enum MyEnum {
@JsonProperty("7")
FOO,
@JsonProperty("42")
BAR
}
@JsonFormat(shape = JsonFormat.Shape.NUMBER)
public enum NonNumericEnum {
@JsonProperty("NOT_A_NUMBER")
VALUE
}
private final ObjectMapper MAPPER = newJsonMapper();
@Test
public void shouldDeserializeFromNumericAndQuotedNumericIndex() throws Exception {
assertEquals(MyEnum.FOO, MAPPER.readValue("7", MyEnum.class));
assertEquals(MyEnum.FOO, MAPPER.readValue(q("7"), MyEnum.class));
}
@Test
public void shouldDeserializeEnumMapKeysUsingNumericJsonPropertyIndex() throws Exception {
JavaType type = MAPPER.getTypeFactory().constructMapType(HashMap.class, MyEnum.class, String.class);
Map<MyEnum, String> result = MAPPER.readValue(a2q("{'7':'lucky'}"), type);
assertEquals(1, result.size());
assertEquals("lucky", result.get(MyEnum.FOO));
}
@Test
public void shouldDeserializeNonNumericJsonPropertyFromStringWithNumberShape() throws Exception {
// Non-numeric @JsonProperty with Shape.NUMBER: string input matches by name
assertEquals(NonNumericEnum.VALUE, MAPPER.readValue(q("NOT_A_NUMBER"), NonNumericEnum.class));
}
@Test
public void shouldFallbackToOrdinalForNumericInputWhenJsonPropertyIsNotNumeric() throws Exception {
// Numeric input with non-numeric @JsonProperty: falls back to ordinal
assertEquals(NonNumericEnum.VALUE, MAPPER.readValue("0", NonNumericEnum.class));
}
@Test
public void shouldNotUseNumericJsonPropertyIndexWithoutNumberShape() throws Exception {
ObjectMapper mapper = jsonMapperBuilder().build();
// numeric token: should NOT treat @JsonProperty("7"/"42") as numeric index
assertThrows(MismatchedInputException.class, () -> mapper.readValue("7", MyEnumNoFormat.class));
assertThrows(MismatchedInputException.class, () -> mapper.readValue("42", MyEnumNoFormat.class));
// string token: should map by NAME (i.e. @JsonProperty), regardless of number-shape
assertEquals(MyEnumNoFormat.FOO, mapper.readValue(q("7"), MyEnumNoFormat.class));
assertEquals(MyEnumNoFormat.BAR, mapper.readValue(q("42"), MyEnumNoFormat.class));
}
@Test
public void shouldNotUseNumericJsonPropertyIndexWithoutNumberShapeEvenWhenGlobalIndexFeatureIsEnabled() throws Exception {
ObjectMapper mapper = jsonMapperBuilder()
.enable(EnumFeature.WRITE_ENUMS_USING_INDEX)
.build();
// still must not treat numeric @JsonProperty as numeric index
assertThrows(MismatchedInputException.class, () -> mapper.readValue("7", MyEnumNoFormat.class));
assertThrows(MismatchedInputException.class, () -> mapper.readValue("42", MyEnumNoFormat.class));
// but quoted values are names -> should work
assertEquals(MyEnumNoFormat.FOO, mapper.readValue(q("7"), MyEnumNoFormat.class));
assertEquals(MyEnumNoFormat.BAR, mapper.readValue(q("42"), MyEnumNoFormat.class));
}
}