New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
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 吧 |
Fix generic field deserialize, issue #3810
#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: