This repository has been archived by the owner on Oct 23, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 6.5k
1.2.76中BugFix#3693的修复代码又引入了新的Bug! #3810
Comments
提供下测试用例? |
我们本身的场景是对Spring MVC的 package com.dw.infinite.junit5;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.util.ParameterizedTypeImpl;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.google.common.reflect.TypeToken;
import lombok.Data;
import org.junit.jupiter.api.Test;
import java.lang.reflect.Type;
public class FastJsonTest {
@Data
static class TestA<T> {
int a1;
T a2;
}
@Data
static class TestB<T> {
String b1;
T b2;
}
@Test
void test() throws JsonProcessingException {
String json = "{\"a1\":99,\"a2\":{\"b1\":\"b1\",\"b2\":\"b2\"}}";
TestA<?> ret1 = null;
TestA<?> ret2 = null;
TypeToken<TestB<String>> tt = new TypeToken<TestB<String>>() {};
Type bType = tt.getType();
Type realType = new ParameterizedTypeImpl(new Type[]{ bType }, TestA.class, TestA.class);
JSONObject jo = JSONObject.parseObject(json);
ret1 = jo.toJavaObject(realType);
ret2 = JSON.parseObject(json, realType);
System.out.println(ret1.getA2().getClass().getName());
System.out.println(ret2.getA2().getClass().getName());
}
} 同一段代码,1.2.76的输出是,通过调试也能看到,这个结果跟上一个版本不一致,也不是我们要的结果:
1.2.75的输出是正确的,通过调试跟进去看也能发现类型是对的:
另外你看我贴的代码,1.2.76里面的代码实现是有点问题的,这块具体代码我不是特别清楚,但是看 if (fieldValueDeserilizer == null) { // 该处修改导致下面一行失效,感觉这个值可能恒不为null
fieldValueDeserilizer = parser.getConfig().getDeserializer(fieldType); // 代码失效,原有逻辑无法正确执行
} 这一块觉得代码块里的代码可能会失效,实际上我们的场景中1.2.76的代码就失效了。 |
已提供,请参考。 |
我也遇到了这样的问题,且由于受到TypeReference的缓存影响,该问题十分隐蔽且难以复现 import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.TypeReference;
import com.alibaba.fastjson.util.ParameterizedTypeImpl;
import lombok.Data;
import org.junit.Test;
import java.lang.reflect.Type;
import java.util.List;
public class FastJsonTest {
@Data
static class TestA<T> {
T a;
}
@Data
static class TestB {
String b;
}
private final static String json = "{\"a\":[{\"b\":\"b\"}]}";
/**
* DefaultFieldDeserializer的parseField方法在1.2.76中67行引入了一个null判断,修复了@JSONField注解自定义反序列化器失效的问题#3693,
* 但对于没有使用这个注解自定义反序列化器的情况,原本是通过68行获取实际运行时类型fieldType匹配的反序列化器,
* 由于通过55行getFieldValueDeserilizer始终能获取到默认的普通Object通用反序列化器,null判断始终为false使这个逻辑失效了,
* 从而导致反序列化使用了默认的普通Object通用反序列化器,将list反序列化为JSONArray,将对象反序列化为JSONObject,
* 后续逻辑处理就会抛出java.lang.ClassCastException: com.alibaba.fastjson.JSONObject cannot be cast to ...
*
* @see com.alibaba.fastjson.parser.deserializer.DefaultFieldDeserializer
*/
// @Test
public void testError() {
System.out.println("---------------testError---------------");
ParameterizedTypeImpl inner = new ParameterizedTypeImpl(new Type[]{TestB.class}, List.class, List.class);
ParameterizedTypeImpl outer = new ParameterizedTypeImpl(new Type[]{inner}, TestA.class, TestA.class);
JSONObject jo = JSONObject.parseObject(json);
//为了打印出b的className这里将返回值改为TestA<List<?>>,否则会抛出ClassCastException
TestA<List<?>> ret = jo.toJavaObject(outer);
System.out.println("a class name: " + ret.getA().getClass().getName());
System.out.println("b class name: " + ret.getA().get(0).getClass().getName());
}
/**
* 且由于受到TypeReference的缓存影响,该问题十分隐蔽且难以复现
* 如果先调用错误方法,后续即使调用相同泛型的正确方法也会全部解析报错
* 如果先调用正确方法,后续调用相同泛型的正确方法就不会出现问题
*
* @see com.alibaba.fastjson.TypeReference
*/
@Test
public void testErrorFirst() {
testError();
testOk();
}
@Test
public void testOkFirst() {
testOk();
testError();
testOk();
}
// @Test
public void testOk() {
testOk1();
testOk2();
}
// @Test
public void testOk1() {
System.out.println("---------------testOk1---------------");
TestA<List<?>> ret = JSON.parseObject(json, new TypeReference<TestA<List<TestB>>>() {
}.getType());
System.out.println("a class name: " + ret.getA().getClass().getName());
System.out.println("b class name: " + ret.getA().get(0).getClass().getName());
}
// @Test
public void testOk2() {
System.out.println("---------------testOk2---------------");
ParameterizedTypeImpl inner = new ParameterizedTypeImpl(new Type[]{TestB.class}, List.class, List.class);
ParameterizedTypeImpl outer = new ParameterizedTypeImpl(new Type[]{inner}, TestA.class, TestA.class);
TestA<List<?>> ret = JSONObject.parseObject(json, outer);
System.out.println("a class name: " + ret.getA().getClass().getName());
System.out.println("b class name: " + ret.getA().get(0).getClass().getName());
}
} |
您好,现在有在修复吗? |
@darren-wang soory, 最近工作太忙了, 你有兴趣直接发个 pr 吧 |
This was referenced Jun 30, 2021
Open
wenshao
added a commit
that referenced
this issue
Jul 10, 2021
Fix generic field deserialize, issue #3810
Sign up for free
to subscribe to this conversation on GitHub.
Already have an account?
Sign in.
#3693
上面的 #3639 提出了一个bug,即通过
@JSONField#deserializeUsing
属性指定的自定义反序列化器被后续的代码覆盖,并在1.2.76中进行了修复,然而我们在使用升级后的1.2.76时发现1.2.75中没有问题的代码出现报错,经定位是该Issue的解决方案引入了新的Bug。我们的代码是构造了一个
ClassA<ClassB<String>>
这种样式的类,ClassA<T>
的声明中有一个字段T data
,实际类型是ClassB<String>
,现在1.2.76的修复方案,虽然确保了@JSONField#deserializeUsing
属性指定的自定义反序列化器具有最高的优先级,但是在我们的场景下,并没有使用@JSONField
注解,原本ClassA
中T data
字段的反序列化器应该是针对运行时实际类型ClassB<String>
创建的,现在却获取到的是一个普通的Object
的通用反序列化器。具体代码如下,1.2.76中:
这个方法无论成员变量
fieldValueDeserilizer
初始的状态是否为null
,该方法执行后,成员变量fieldValueDeserilizer
都会被转为非null
的值,考虑了通过@JSONField
注解自定义反序列化器的场景。但是在下面的方法中:
1.2.76中的67行进行了一个
null
判断,但是ObjectDeserializer fieldValueDeserilizer = this.fieldValueDeserilizer
即局部变量fieldValueDeserilizer
正是成员变量this.fieldValueDeserilizer
,而后者如上面所说的,在该方法调用上面的getFieldValueDeserilizer
之后永远不会为null
,所以导致68行代码不会被执行,而之前的版本能够处理这种嵌套的场景,原因就在于68行获取了一个与实际运行时类型匹配的反序列化器,现在这样的修复方案使得68行代码失效了,从而嵌套泛型的场景下失效,将给现有生产代码造成巨大影响The text was updated successfully, but these errors were encountered: