public class BaseResponse<T> {
private Response<T> response;
public Response<T> getResponse() {
return response;
}
public void setResponse(Response<T> response) {
this.response = response;
}
public static class Info{
private int code;
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
}
public static class Response<T>{
private T content;
private Info info;
public T getContent() {
return content;
}
public void setContent(T content) {
this.content = content;
}
public Info getInfo() {
return info;
}
public void setInfo(Info info) {
this.info = info;
}
}
}
将外层类类型形参传递给内层类之后,内层类无法正确解析,只能解析成为JSONObject。
JSON.parseObject(jsonStr,type);
通过以上的方式反序列化,type的类型为Type,非Class。
最终引用的时候,会报出异常:
com.alibaba.fastjson.JSONObject cannot be cast to com.ssqian.bestsign.sign.model.entities.login.LoginResponse$Body
LoginResponse的代码如下
public class LoginResponse extends BaseResponse<LoginResponse.Body>{
public static class Body{
private MemberInfo memberinfo;
public MemberInfo getMemberinfo() {
return memberinfo;
}
public void setMemberinfo(MemberInfo memberinfo) {
this.memberinfo = memberinfo;
}
}
public static class MemberInfo {
private String name;
private String email;
/*
省略Getter,Setter
*/
}
}
问题确实存在,但还没想好怎么解决,下个版本1.2.12再修复
我使用1.1.51.android 也出现这个问题 请问有解决方法吗
问题已经解决,已经在fastjson-1.2.12-SNAPSHOT & 1.1.52.android-SNAPSHOT上修复此问题,这两个的正式版本预计5月22日发布
谢谢,问题解决了,可以关闭这个issue了。
public class Bug_for_issue_569 extends TestCase {
public void test_for_issue() throws Exception {
LoginResponse loginResp = new LoginResponse();
loginResp.response = new Response<LoginResponse.Body>();
loginResp.response.content = new Body();
loginResp.response.content.setMemberinfo(new MemberInfo());
loginResp.response.content.getMemberinfo().name = "ding102992";
loginResp.response.content.getMemberinfo().email = "[email protected]";
String text = JSON.toJSONString(loginResp);
LoginResponse loginResp2 = JSON.parseObject(text, LoginResponse.class);
Assert.assertEquals(loginResp.response //
.getContent() //
.getMemberinfo().name, //
loginResp2.response //
.getContent() //
.getMemberinfo().name);
Assert.assertEquals(loginResp.response //
.getContent().getMemberinfo().email, //
loginResp2.response.getContent().getMemberinfo().email);
String str = "{\"bList\":[{\"data\":[0,1]},{\"data\":[1,2]},{\"data\":[2,3]},{\"data\":[3,4]},{\"data\":[4,5]},{\"data\":[5,6]},{\"data\":[6,7]},{\"data\":[7,8]},{\"data\":[8,9]},{\"data\":[9,10]}]}";
A<Integer> aInteger;
A<Long> aLong;
Gson gson = new Gson();
aInteger = gson.fromJson(str, new TypeToken<A<Integer>>() {
}.getType());
Assert.assertEquals(aInteger.getbList().get(0).getData().get(0).getClass().getName(), Integer.class.getName());
aInteger = JSON.parseObject(str, new TypeReference<A<Integer>>() {
});
Assert.assertEquals(aInteger.getbList().get(0).getData().get(0).getClass().getName(), Integer.class.getName());
aLong = gson.fromJson(str, new TypeToken<A<Long>>() {
}.getType());
Assert.assertEquals(aLong.getbList().get(0).getData().get(0).getClass().getName(), Long.class.getName());
aLong = JSON.parseObject(str, new TypeReference<A<Long>>() {
});
Assert.assertEquals(aLong.getbList().get(0).getData().get(0).getClass().getName(), Long.class.getName());
}
public static class BaseResponse<T> {
public Response<T> response;
}
public static class Response<T> {
private T content;
public T getContent() {
return content;
}
public void setContent(T content) {
this.content = content;
}
}
public static class LoginResponse extends BaseResponse<LoginResponse.Body> {
public static class Body {
private MemberInfo memberinfo;
public MemberInfo getMemberinfo() {
return memberinfo;
}
public void setMemberinfo(MemberInfo memberinfo) {
this.memberinfo = memberinfo;
}
}
public static class MemberInfo {
public String name;
public String email;
/*
* 省略Getter,Setter
*/
}
}
public static class A<T> {
private List<B<T>> bList;
public List<B<T>> getbList() {
return bList;
}
public void setbList(List<B<T>> bList) {
this.bList = bList;
}
}
public static class B<T> {
private List<T> data;
public List<T> getData() {
return data;
}
public void setData(List<T> data) {
this.data = data;
}
}
}
添加了一个测试用例,这个bug还有,用gson就没问题。上面的测试例子不能通过。嵌套的对象应该是Long,结果却是Integer。
public static class RequestEntry
......
Result
......
}
在1.1.52.android上这个问题还是存在,请问是否是使用方式不正确?
你好, 我在Android上也遇到了这个问题(泛型嵌套,转换异常), 使用的是1.1.52.android jar包。
说明:
我主要是在android.test包下,使用JUnit框架测试的:当使用Method的方式测试时, 没有出现该异常;当使用Class的方式测试时,会100%出现。
我试着在app中直接parseObject是可以正常转换的,所以我不确定这是在测试环境下的问题,还是在Android上也可能存在
我使用1.2.13版本还是不行啊,我不是Android的,是用的正常web版本。
@LichFaker 我也遇到这个问题了。用的最新版1.1.52还是存在这个问题。请问你后来咋解决的?
@nziyouren 目前我没有好的解决方案, 你可以不要使用嵌套的泛型或者使用别的解析库代替
看来多人遇到了此问题,我会尽快跟进解决
非常感谢 @luckiss 反馈了此问题,已经重现并且解决,将会在下个版本 1.2.16中带上,预计在8月14日(周日)发布
1.1.52.android也存在此问题,已修正,将会在下个版本1.1.53.android中解决此问题,预计在8月14日发布
你好 1.2.15中这种复杂的泛型嵌套还未解决,1.2.16 在8.14号发布能解决该问题么?
我现在用1.2.15还是提示这个
" com.alibaba.fastjson.JSONException: syntax error
@ding102992 遇到泛型的问题能解决,@liuzhigang1237 你遇到的问题最好能够提供testcase,我验证一下
@wenshao 我发现最新版android分支依然存在问题,但不是百分百必现。我发现我的APP奔溃后,再次进入APP,部分泛型不能解析可能性较大,而且不是所有泛型都不能解析。因为我这边调用逻辑很简单,请问我能怎么做才能准确复现这个bug,并让你修复?
@wenshao 就是如下这种结构的:
public class ResponseDO<T> {
private String code;
private T dataResult;
}
我要存成json的是这样的一个结构
ResponseDO<List<Student>>
@wenshao 你好,反馈个问题,泛型嵌套超过2层无法正确解析泛型类型的问题依然存在
问题没有重现
我的也出现了,
class PeiqiResponse<T> {
Boolean success;
Integer errCode;
String errDes;
T result;
}
声明:PeiqiResponse<List<Dept>>
调试分析
经过多次调试,问题出现在这里 DefaultFieldDeserializer#parseField
@Override
public void parseField(DefaultJSONParser parser, Object object, Type objectType, Map<String, Object> fieldValues) {
if (fieldValueDeserilizer == null) {
getFieldValueDeserilizer(parser.getConfig());
}
if (objectType instanceof ParameterizedType) {
ParseContext objContext = parser.getContext();
objContext.type = objectType;
fieldType = FieldInfo.getFieldType(this.clazz, objectType, fieldType);
}
如我的对象类型 result 的类型是 ListfieldValueDeserilizer ==JavaObjectDeserializer, 然后在 68行 进行解析处理
68 value = fieldValueDeserilizer.deserialze(parser, fieldType, fieldInfo.name);
接着分析 JavaObjectDeserializer
public <T> T deserialze(DefaultJSONParser parser, Type type, Object fieldName) {
if (type instanceof GenericArrayType) {
Type componentType = ((GenericArrayType) type).getGenericComponentType();
if (componentType instanceof TypeVariable) {
TypeVariable<?> componentVar = (TypeVariable<?>) componentType;
componentType = componentVar.getBounds()[0];
}
List<Object> list = new ArrayList<Object>();
parser.parseArray(componentType, list);
Class<?> componentClass;
if (componentType instanceof Class) {
componentClass = (Class<?>) componentType;
Object[] array = (Object[]) Array.newInstance(componentClass, list.size());
list.toArray(array);
return (T) array;
} else {
return (T) list.toArray();
}
}
if (type instanceof Class && type != Object.class && type != Serializable.class) {
return (T) parser.parseObject(type);
}
return (T) parser.parse(fieldName);//最后到了这里,
//而 parser == DefaultJSONParser (来源于 `DefaultJSONParser (614) return (T) derializer.deserialze(this, type, fieldName);`)
}
然后进入 DefaultJSONParser 1280 行 parse(Object fieldName) ,在这里就将result的值解析成了 JSONArray
解决方案:
回到来这里 DefaultFieldDeserializer#parseField
@Override
public void parseField(DefaultJSONParser parser, Object object, Type objectType, Map<String, Object> fieldValues) {
if (fieldValueDeserilizer == null) {
getFieldValueDeserilizer(parser.getConfig());
}
if (objectType instanceof ParameterizedType) {
ParseContext objContext = parser.getContext();
objContext.type = objectType;
fieldType = FieldInfo.getFieldType(this.clazz, objectType, fieldType);
}
既然是多级泛型 ParameterizedType 并且解析除了泛型类型 fieldType ,为什么不加一行
fieldValueDeserilizer = parser.getConfig().getDeserializer(fieldType)
这样从我贴的数据中就得到了 fieldValueDeserilizer = CollectionCodec,这样就根据 fieldType获取到了正确的 fieldValueDeserilizer
@wenshao 这样是否能解决?
我会复现了,是由于fastjson derializers 缓存的问题:
1. 复现
过程:
mType = new TypeReference<MyResponse<List<Dept>>>() {
}.getType();
mType1 = new TypeReference<MyResponse>() {
}.getType();
JSON.parseObject(jsonData, mType1, configBug569, featureValues,
features != null ? features : EMPTY_SERIALIZER_FEATURES);, 结果:resp.getResult().getClass()==JSONArray.classMyResponse<List<Dept>> JSON.parseObject(jsonData, mType, configBug569, featureValues, features != null ? features : EMPTY_SERIALIZER_FEATURES); 结果:resp.getResult().getClass()==ArrayList.class2.分析
第一次调用反序列化,关键点: ParserConfig(460)
460 putDeserializer(type, derializer);
这里缓存了对于 MyResponse 的解析器
第二次调用反序列化:
ParserConfig(352-354行)
if (type instanceof WildcardType || type instanceof TypeVariable || type instanceof ParameterizedType) {
derializer = derializers.get(clazz);
}
这里经过代码(337 derializers.get(type))没有找到指定type的解析器,然后到352行判断如果type是泛型,就使用class代替type从缓存中获取解析器,这样就获取到了MyResponse的解析器,而并非是MyResponse>的解析器。
结论:
解析器缓存导致,然而ParserConfig默认都是使用 的 ParserConfig.getGlobalInstance(),从而缓存造成了影响。
3. 解决方案
fieldType = FieldInfo.getFieldType(this.clazz, objectType, fieldType);。请使用最新版本的1.1.55.android试试看
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.21</version>
</dependency>
这个版本依然无法访问引用的T类型的get()
@wenshao Android1.1.55.android还是会偶发, ;
public class ResponseBean<T> {
public String apiId;
public StatusBean status;
public Object page_info;
public T bizobj;
}
//解析
{
resp= JSON.parseObject(respStr, ResponseBean.getTypeArray(LifeServiceBean.class));
}
//为解析器指定type
public static Type getTypeObj(Class... classes) {
if (classes == null || classes.length <= 0)
return null;
else
return new ParameterizedTypeImpl(ResponseBean.class, classes);
}
public static Type getTypeArray(Class... classes) {
Type listType = new ParameterizedTypeImpl(ArrayList.class, classes);
if (listType == null)
return null;
else
return new ParameterizedTypeImpl(ResponseBean.class, new Type[]{listType});
}
当泛型T指定为ArrayList<xxx.class>时,会发生java.lang.ClassCastException: com.alibaba.fastjson.JSONArray cannot be cast to java.util.ArrayList而且在我的项目中,app注册以后发起的第一个请求是会必现的,
之后就正常了;
@Zhangxxl 你的代码编译不过
@wenshao
这里还有一个自定义的ParameterizedTypeImpl ;
public class ParameterizedTypeImpl implements ParameterizedType {
private final Class raw;
private final Type[] args;
public ParameterizedTypeImpl(Class raw, Type[] args) {
this.raw = raw;
this.args = args != null ? args : new Type[0];
}
@Override
public Type[] getActualTypeArguments() {
return args;
}
@Override
public Type getRawType() {
return raw;
}
@Override
public Type getOwnerType() {
return null;
}
}
而且这个ClassCastException只在用户注册后第一次登陆发生,我也抓包看过了,服务器返回的json是一模一样的
@wenshao
你好,这段代码可以重现泛型多层嵌套不能正确解析的问题,使用的是1.2.23版本的fastjson,请帮忙解决下,谢谢!
public class App
{
public static void main( String[] args ) throws IOException
{
String str1="{\n" +
" "matches":77085,\n" +
" "groups":[{\n" +
" "groupValue":1,\n" +
" "doclist":{"numFound":8945,"start":0,"docs":[\n" +
" {\n" +
" "id":3157808,\n" +
" "title":"朗境 2014款 1.6L 自动型",\n" +
" "provid":540000,\n" +
" "cityid":542200}]\n" +
" }},\n" +
" {\n" +
" "groupValue":15,\n" +
" "doclist":{"numFound":2894,"start":0,"docs":[\n" +
" {\n" +
" "id":3157809,\n" +
" "title":"宝马4系 2014款 428i xDrive风尚设计套装",\n" +
" "provid":540000,\n" +
" "cityid":540100}]\n" +
" }}]}";
String str2="{\n" +
" \"matches\":51030,\n" +
" \"groups\":[{\n" +
" \"groupValue\":3864,\n" +
" \"doclist\":{\"numFound\":35,\"start\":0,\"docs\":[\n" +
" {\n" +
" \"keyword\":\"330000_RALLY FIGHTER\",\n" +
" \"typetag\":2}]\n" +
" }},\n" +
" {\n" +
" \"groupValue\":813,\n" +
" \"doclist\":{\"numFound\":35,\"start\":0,\"docs\":[\n" +
" {\n" +
" \"keyword\":\"330000_起亚 福瑞迪\",\n" +
" \"typetag\":2}]\n" +
" }}]}";
String str3="{\n" +
" \"groupValue\":1,\n" +
" \"doclist\":{\"numFound\":8945,\"start\":0,\"docs\":[\n" +
" {\n" +
" \"id\":3157808,\n" +
" \"title\":\"朗境 2014款 1.6L 自动型\",\n" +
" \"provid\":540000,\n" +
" \"cityid\":542200}]\n" +
" }}";
String str4="{\n" +
" \"groupValue\":3864,\n" +
" \"doclist\":{\"numFound\":35,\"start\":0,\"docs\":[\n" +
" {\n" +
" \"keyword\":\"330000_RALLY FIGHTER\",\n" +
" \"typetag\":2}]\n" +
" }}";
// 嵌套两层可以解析
Group
Group
// 嵌套三层无法解析
//Result<Doc1> test1=JSON.parseObject(str1,new TypeReference<Result<Doc1>>(){});
//Result<Doc2> test2=JSON.parseObject(str2,new TypeReference<Result<Doc2>>(){});
}
}
class Doc1
{
private int id;
private String title;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
}
class Doc2
{
private String keyword;
private int typetag;
public String getKeyword() {
return keyword;
}
public void setKeyword(String keyword) {
this.keyword = keyword;
}
public int getTypetag() {
return typetag;
}
public void setTypetag(int cid) {
this.typetag = typetag;
}
}
class Docs
{
private int numFound;
private int start;
private T[] docs;
public int getNumFound() {
return numFound;
}
public void setNumFound(int numFound) {
this.numFound = numFound;
}
public int getStart() {
return start;
}
public void setStart(int start) {
this.start = start;
}
public T[] getDocs() {
return docs;
}
public void setDocs(T[] docs) {
this.docs = docs;
}
}
class Group
{
private int groupValue;
private Docs doclist;
public int getGroupValue() {
return groupValue;
}
public void setGroupValue(int groupValue) {
this.groupValue = groupValue;
}
public Docs
return doclist;
}
public void setDoclist(Docs
this.doclist = doclist;
}
}
class Result
{
private int matches;
private Group[] groups;
public int getMatches() {
return matches;
}
public void setMatches(int matches) {
this.matches = matches;
}
public void setGroups(Group
this.groups = groups;
}
public Group
return groups;
}
}
同样遇到这个问题,我用的版本是最新的1.2.24,请问什么时候可以修复呢?
主要是 解析器缓存导致 结合retroft以后 每次转换泛型传入不一致,第二次解析用了上次的缓存的泛型 ,因此转换失败 需要在没有传入泛型的接口传入Void就可以了 例如:ResponseBean<Void>
android 版的 1.1.57 配合 retrofit 还没有解决这个问题~
fastjson-1.2.32.jar 依然没有解决
多层泛型 toJSONString(), 出现 classA can not cast to classA 这种情况
@wenshao 你好
com.alibaba:fastjson:1.2.31 多层泛型反序列化会丢失类型。
@Data
public class MyTable
final private Map
...
}
MyTable
在table中,MyValue类型被反序列化成了JSONObject。请帮忙解决一下,谢谢啦。
同样遇到了这个问题,以至搞到半夜。
版本 1.1.58 配合Retrofit2使用,线上大量偶发,均为 com.alibaba.fastjson.JSONObject cannot be cast to com.*
根据大家建议,暂时替换为了Gson,希望问题能够尽快解决,还是习惯FastJson。
收到,尽快跟进处理
我也遇到解析器缓存的问题
@wangsai-silence 问题已修复,很遗憾没在1.1.59.android中带上,预计下周或者下下周再发一个android版本修复此问题。
@wenshao 1.1.61.android还是会出现泛型解析不彻底的情况
public class Resource<T> {
private Status status;
private int ret;
private String message;
private T data;
}
public class App {
private String appId;
}
class Test<T> {
String str= "{\"ret\":0,\"msg\":\"ok\",\"data\":[{\"appId\":\"11c53f541dee4f5bbc4f75f99002278c\"},{\"appId\":\"c6102275ce5540a59424defa1cccb8ed\"}]}";
Test() {
Resource<T> resource = JSON.parseObject(str, new TypeReference<Resource<T>>(){});
Log.d(TAG, resource + "");
}
}
调用方法为:
new Test<ArrayList<App>>();

1.2.38依然存在
现在泛型多层嵌套的问题还是没有解决?
1.1.67仍然有这个问题,请问有解决方案了吗
1.2.44 还是有这个问题
1.2.44还是有问题,代码示例如下:
public class InterfaceResult<T> extends BaseInterfaceResult
{
public T getResult() {
return result;
}
public void setResult(T result) {
this.result = result;
}
private T result;
}
@dbaxyx 能提供完整的testcase么?问题没重现
@wenshao
问题出在InterfaceResult
InterfaceResult<Citys> resultObj;
public class BaseInterfaceResult
{
private int returncode;
public int getReturncode() {
return returncode;
}
public void setReturncode(int returncode) {
this.returncode = returncode;
}
public String getMessage() {
return message;
}
public void setMessage(String message) {
this.message = message;
}
private String message;
}
public class InterfaceResult<T> extends BaseInterfaceResult
{
public T getResult() {
return result;
}
public void setResult(T result) {
this.result = result;
}
private T result;
}
public class Citys
{
public List<City> getItems() {
return items;
}
public void setItems(List<City> items) {
this.items = items;
}
public List<City> items;
}
public class City {
private int parentid;
private String provincename;
private int cityid;
private String cityname;
private int enginenumlen;
private int framenumlen;
private int support;
private String firstletter;
public int getParentid() {
return parentid;
}
public void setParentid(int parentid) {
this.parentid = parentid;
}
public String getProvincename() {
return provincename;
}
public void setProvincename(String provincename) {
this.provincename = provincename;
}
public int getCityid() {
return cityid;
}
public void setCityid(int cityid) {
this.cityid = cityid;
}
public String getCityname() {
return cityname;
}
public void setCityname(String cityname) {
this.cityname = cityname;
}
public int getEnginenumlen() {
return enginenumlen;
}
public void setEnginenumlen(int enginenumlen) {
this.enginenumlen = enginenumlen;
}
public int getFramenumlen() {
return framenumlen;
}
public void setFramenumlen(int framenumlen) {
this.framenumlen = framenumlen;
}
public int getSupport() {
return support;
}
public void setSupport(int support) {
this.support = support;
}
public String getFirstletter() {
return firstletter;
}
public void setFirstletter(String firstletter) {
this.firstletter = firstletter;
}
}
json字符串根据对象生成一个,然后反序列化一下再做test case
1.2.48 还存在该问题, jdk1.8
fastjson : '1.2.47' kotlin 1.2.40 依然存在多级泛型嵌套不解析成对应对象而是JSONObject
val reference = object : TypeReference
val resBody = response.body()?.string()!!
val result = JSONObject.parseObject(resBody, reference)
if (result.code == Constant.OK_CODE) {
onRequestListener.onSuccess(result.data)
} else {
onRequestListener.onFail(result.msg,result.code)
}
public class Result
private int code;
private String msg;
private T data;
public Result(){}
public Result(int code, String msg, T data) {
this.code = code;
this.msg = msg;
this.data = data;
}
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
public T getData() {
return data;
}
public void setData(T data) {
this.data = data;
}
}
1.2.47 还是不能解析多级泛型
我换成1.2.30版本的jar包,能正常解析多级泛型了
1.2.39问题依旧,泛型多重解析,最底层的对象变成了HashMap;
Gson可以序列化!
我可以把具体的泛型计算出来,但是该怎么做呢?
感觉这个bug是个无底洞呀
com.alibaba:fastjson:1.2.49
依然存在此bug……
1.2.49 +1
// https://mvnrepository.com/artifact/com.alibaba/fastjson
compile group: 'com.alibaba', name: 'fastjson', version: '1.2.49'
version: '1.2.49' ++++1
为何到今天我不管用哪个版本此问题依然存在?有正常使用的同学吗?哪个版本?实在不行也只有换Gson了
是的,多层泛型嵌套fastjson不行,gson却正常,值得参考下gson的实现方式
我在1.2.49版本遇到的问题, 经测试在1.2.56版本已被修复
为何到今天我不管用哪个版本此问题依然存在?有正常使用的同学吗?哪个版本?实在不行也只有换Gson了
1.2.56
1.2.56 依旧存在这个问题
当 bean 的成员变量为 Map
这是确实存在,间歇性报jsonobject转实体类出错
@zhishengzhang 能否提供下报错的测试用例
1.2.56问题依旧存在
1.2.58问题依旧存在
关闭重复引用解析后,重复引用属性的@type全部变为JSONObject,导致解析失败,版本1.2.58
我使用的是1.2.7版本,好像还是没有解决,作者可否说明一下解决的版本及代码是如何编写的
我用的是1.2.75版本,也还没有解决...
Most helpful comment
android 版的 1.1.57 配合 retrofit 还没有解决这个问题~