Is @JsonCreator support both DELEGATING mode and PROPERTIES mode deserialization for Enums?
Search before asking
- [x] I searched in the issues and found nothing similar.
Describe the bug
I want to use @JsonCreator on Java enum to achieve deserialization supporting both DELEGATING mode and PROPERTIES mode. But I found that it may be unavailable for version 2.13.1 (it's ok for version 2.19.2) . Is there any other way to achieve that for version 2.13.1, or is upgrading the version the only option?
Code:
@Getter
@RequiredArgsConstructor
@JsonFormat(shape = JsonFormat.Shape.OBJECT)
@JsonIncludeProperties({"code", "desc"})
public enum ChannelEnum {
ALIPAY(0, "支付宝"),
WECHAT(1, "微信")
;
private final int code;
private final String desc;
@Nullable
@JsonCreator
private static ChannelEnum ofCode(@JsonProperty("code") String code) {
if (code == null) {
return null;
}
return Arrays.stream(values()).filter(channelEnum -> channelEnum.getCode() == Integer.parseInt(code)).findFirst().orElse(null);
}
}
public class CreatorTest extends TestCase {
private final ObjectMapper objectMapper = new ObjectMapper();
public void testProperties() throws JsonProcessingException {
String json = "{\"code\": 1}";
ChannelEnum channel = objectMapper.readValue(json, ChannelEnum.class);
Assert.assertSame(channel, ChannelEnum.WECHAT);
}
public void testDelegating() throws JsonProcessingException {
String json = "1";
ChannelEnum channel = objectMapper.readValue(json, ChannelEnum.class);
Assert.assertSame(channel, ChannelEnum.WECHAT);
}
public void testNoCodeProperty() throws JsonProcessingException {
String json = "{\"desc\": \"支付宝\"}";
ChannelEnum channel = objectMapper.readValue(json, ChannelEnum.class);
Assert.assertNull(channel);
}
}
stack trace for version 2.13.1
com.fasterxml.jackson.databind.exc.MismatchedInputException: Input mismatch reading Enum `org.examplel.jackson.view.ChannelEnum`: properties-based `@JsonCreator` ([method org.examplel.jackson.view.ChannelEnum#ofCode(java.lang.String)]) expects JSON Object (JsonToken.START_OBJECT), got JsonToken.VALUE_NUMBER_INT
at [Source: (String)"1"; line: 1, column: 1]
at com.fasterxml.jackson.databind.exc.MismatchedInputException.from(MismatchedInputException.java:59)
at com.fasterxml.jackson.databind.DeserializationContext.reportInputMismatch(DeserializationContext.java:1741)
at com.fasterxml.jackson.databind.deser.std.FactoryBasedEnumDeserializer.deserialize(FactoryBasedEnumDeserializer.java:137)
at com.fasterxml.jackson.databind.deser.DefaultDeserializationContext.readRootValue(DefaultDeserializationContext.java:322)
at com.fasterxml.jackson.databind.ObjectMapper._readMapAndClose(ObjectMapper.java:4674)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3629)
at com.fasterxml.jackson.databind.ObjectMapper.readValue(ObjectMapper.java:3597)
at org.examplel.jackson.view.CreatorTest.testDelegating(CreatorTest.java:28)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at junit.framework.TestCase.runTest(TestCase.java:177)
at junit.framework.TestCase.runBare(TestCase.java:142)
at junit.framework.TestResult$1.protect(TestResult.java:122)
at junit.framework.TestResult.runProtected(TestResult.java:142)
at junit.framework.TestResult.run(TestResult.java:125)
at junit.framework.TestCase.run(TestCase.java:130)
at junit.framework.TestSuite.runTest(TestSuite.java:241)
at junit.framework.TestSuite.run(TestSuite.java:236)
at org.junit.internal.runners.JUnit38ClassRunner.run(JUnit38ClassRunner.java:90)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:69)
at com.intellij.rt.junit.IdeaTestRunner$Repeater$1.execute(IdeaTestRunner.java:38)
at com.intellij.rt.execution.junit.TestsRepeater.repeat(TestsRepeater.java:11)
at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:35)
at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:232)
at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:55)
2.13.x is not an open branch so if it does not work, no fix will be coming -- but you could try latest 2.13 patch, 2.13.5. I don't see any Enum-related fixes in release notes tho.
However: even with later versions, a single Constructor can only be used in one mode: either Delegating or Properties-based. There is issue #5084 to consider allowing that but it has not yet been implemented. So I am not sure how this would be working currently for Enums, in any version?
2.13.x is not an open branch so if it does not work, no fix will be coming -- but you could try latest 2.13 patch, 2.13.5. I don't see any Enum-related fixes in release notes tho.
However: even with later versions, a single Constructor can only be used in one mode: either Delegating or Properties-based. There is issue #5084 to consider allowing that but it has not yet been implemented. So I am not sure how this would be working currently for Enums, in any version?
Alright, I want to use @JsonFormat(shape = JsonFormat.Shape.OBJECT) on an enum and allow the front end to request using the Delegating mode. However, if Delegating and Properties are incompatible, it could lead to a very awkward situation: the result serialized from the enum itself cannot be deserialized.