fastjson2
fastjson2 copied to clipboard
[BUG] 序列化枚举类如果是负数会直接crash
问题描述
简要描述您碰到的问题。 在序列化枚举类时有负数的情况
环境信息
请填写以下信息:
- OS信息: [e.g.:Ubuntu 22.04.3 LTS]
- JDK信息: [e.g.:openjdk 11.0.22 2024-01-16]
- 版本信息:[e.g.:Fastjson 2.0.49 兼容1.x.x]
重现步骤
Test case
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import com.alibaba.fastjson.parser.Feature;
import com.alibaba.fastjson.annotation.JSONField;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
public class Test242 {
@Test
public void testParseObjectWithNegativeEnumValue() {
String jsonStr = "{\"code\": -1}";
Mock m = JSON.parseObject(jsonStr, new TypeReference<Mock>() {}, Feature.SupportAutoType);
assertNotNull(m);
assertEquals(EnumClass.NEGATIVE_ONE, m.getCode());
}
}
class Mock {
@JSONField(name = "code")
private EnumClass code;
public EnumClass getCode() {
return code;
}
public void setCode(EnumClass code) {
this.code = code;
}
}
enum EnumClass {
A(1),
NEGATIVE_ONE(-1);
private final int code;
EnumClass(int code) {
this.code = code;
}
public int getCode() {
return code;
}
public static EnumClass valueOf(int code) {
for (EnumClass enumClass : EnumClass.values()) {
if (enumClass.getCode() == code) {
return enumClass;
}
}
return null;
}
}
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.parser.Feature;
import org.junit.Test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
public class Test243 {
@Test
public void testEnumDeserializationWithNegativeValue() {
String jsonStr = "{\"code\":-1}"; // Updated JSON with a negative code value
Mock m = JSON.parseObject(jsonStr, Mock.class, Feature.AllowISO8601DateFormat);
assertNotNull(m);
assertEquals(-1, m.getCode().getCode()); // Expected to get the code value -1
}
static class Mock {
private EnumClass code;
public EnumClass getCode() {
return code;
}
public void setCode(EnumClass code) {
this.code = code;
}
}
enum EnumClass {
A(1);
private int code;
EnumClass(int code) {
this.code = code;
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
}
}
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.TypeReference;
import org.junit.Test;
import java.lang.reflect.Type;
public class Test244 {
@Test
public void testEnumDeserializationWithNegativeValue() {
String jsonStr = "{\"code\":-1}";
Type type = new TypeReference<Mock>(){}.getType();
Mock m = JSON.parseObject(jsonStr, type);
assert m != null;
assert m.getCode().getCode() == -1;
}
}
class Mock {
private EnumClass code;
public EnumClass getCode() {
return code;
}
public void setCode(EnumClass code) {
this.code = code;
}
}
enum EnumClass {
A(1),
B(-1);
private int code;
EnumClass(int code) {
this.code = code;
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
}
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.annotation.JSONField;
import org.junit.Test;
import java.nio.charset.StandardCharsets;
import java.nio.charset.CharsetDecoder;
import java.lang.reflect.Type;
import com.alibaba.fastjson.parser.Feature;
public class Test251 {
@Test
public void testParseObjectWithNegativeEnumValue() {
byte[] jsonBytes = "{\"code\": -1}".getBytes(StandardCharsets.UTF_8);
CharsetDecoder charsetDecoder = StandardCharsets.UTF_8.newDecoder();
Type clazz = Mock.class;
Feature[] features = new Feature[0];
Mock m = JSON.parseObject(jsonBytes, 0, jsonBytes.length, charsetDecoder, clazz, features);
assert m != null;
assert m.getCode().getCode() == -1;
}
class Mock {
@JSONField(name = "code")
private EnumClass code;
Mock() {}
public EnumClass getCode() {
return code;
}
public void setCode(EnumClass code) {
this.code = code;
}
}
enum EnumClass {
A(1);
private int code;
EnumClass(int code) {
this.code = code;
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
}
}
期待的正确结果
能够正常序列化
相关日志输出
*com.alibaba.fastjson.JSONException: read field 'Test243$Mock.setCode, offset 11, character }, line 1, column 11, fastjson-version 2.0.49 {"code":-1}
at com.alibaba.fastjson.JSON.parseObject(JSON.java:553)
at Test243.testEnumDeserializationWithNegativeValue(Test243.java:13)
at java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:104)
at java.base/java.lang.reflect.Method.invoke(Method.java:578)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
at org.junit.runners.BlockJUnit4ClassRunner$1.evaluate(BlockJUnit4ClassRunner.java:100)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:63)
at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
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)
Caused by: com.alibaba.fastjson2.JSONException: No enum ordinal Test243.EnumClass.-1 at com.alibaba.fastjson2.reader.ObjectReaderImplEnum.readObject(ObjectReaderImplEnum.java:238) at com.alibaba.fastjson2.reader.FieldReaderObject.readFieldValue(FieldReaderObject.java:154) at com.alibaba.fastjson2.reader.ObjectReader1.readObject(ObjectReader1.java:286) at com.alibaba.fastjson.JSON.parseObject(JSON.java:543) ... 26 more。*
源码由于用到了数组,所以判断了 index 不能为负数
https://github.com/alibaba/fastjson2/blob/c86bb8082c7ab2d5efbc04cb6063b6726d84c613/core/src/main/java/com/alibaba/fastjson2/reader/ObjectReaderImplEnum.java#L235-L240
你可以自定义枚举的反序列化,代码如下:
ParserConfig.getGlobalInstance().putDeserializer(EnumClass.class, new ObjectDeserializer() {
@SuppressWarnings("unchecked")
@Override
public <T> T deserialze(final DefaultJSONParser parser, final Type type, final Object fieldName) {
Integer intValue = parser.parseObject(int.class);
if (intValue == -1) {
return (T) EnumClass.NEGATIVE_ONE;
}
return (T) Arrays.stream(EnumClass.values())
.filter(it -> it.getCode() == intValue)
.findFirst()
.orElseThrow(() -> new IllegalArgumentException("No enum value: " + intValue));
}
});
https://oss.sonatype.org/content/repositories/snapshots/com/alibaba/fastjson/2.0.50-SNAPSHOT/ 问题已修复,请帮忙用2.0.50-SNAPSHOT版本在你本地验证下
https://github.com/alibaba/fastjson2/releases/tag/2.0.50 2.0.50已发布,请用新版本