最难调的Bug-序列化引起的血案

描述

由于我利用Gson和ActiveAndroid来保存数据,之前已经能顺利保存各种自定义类型。今天添加一种新的List自定义类型,之后Sqlite疯狂报错,插入出现键重复:
这里写图片描述
我很清楚的记得以前绝对没这错误,而且这条数据绝对存在。
这里写图片描述
为啥用ActiveAndroid的Select出来是null? 我百思不得其解,由于一口气改了太多地方,一度怀疑是事务引起的,由于我用两个线程同时在加载数据,可能一个线程插入了,另一个线程也在操作这数据,就怀疑ActiveAndroid的事务实现有bug。
但是很快就排除了,因为数据库如果没这数据就算报错也应该有把数据插入成功的log,但是只有1条报错的log。说明数据库原来就有这数据。那么就是Select的问题。
通过仔细比较数据,发现有List<\String> picUrls的才会出错。就怀疑是不是数据有问题。

调试

怀疑是序列化出了问题,因为我改过这里。

public class ListStringSerializer extends TypeSerializer {
    @Override
    public Class<?> getDeserializedType() {
        return List.class;
    }

    @Override
    public Class<?> getSerializedType() {
        return String.class;
    }

    @Override
    public String serialize(Object o) {
        // List<String> List<AtUser> List和T均可直接toString
        if (o == null) {
            return null;
        }
//        Log.i("ListStringSerializer", o.toString());
        return o.toString();
    }

    @Override
    public List<String> deserialize(Object o) {
        if (o == null) {
            return null;
        }
        Log.i("ListStringSerializer", "deserialize:" + o.toString());
        List<String> ret = null;
        try {
            ret = new Gson().fromJson((String) o, new TypeToken<List<String>>() {
            }.getType());
        } catch (Exception ex) {
            Log.e("ListStringSerializer", Log.getStackTraceString(ex));
        }

        Log.i("ListStringSerializer", "deserialize ret:" + ret);
        return new Gson().fromJson((String) o, new TypeToken<List<String>>() {}.getType());
    }
}

这下终于报错了:
com.google.gson.JsonSyntaxException: com.google.gson.stream.MalformedJsonException: Unterminated array。
就能确定是数据的问题,导致无法正确序列号。坑爹的是ActiveAndroid对这个反序列化异常不打log也不报错,只是返回一个null。

这是原来的序列化代码:

import android.util.Log;

import com.activeandroid.serializer.TypeSerializer;
import com.google.gson.Gson;
import com.google.gson.reflect.TypeToken;

import java.util.List;

public class ListStringSerializer extends TypeSerializer {
    @Override
    public Class<?> getDeserializedType() {
        return List.class;
    }

    @Override
    public Class<?> getSerializedType() {
        return String.class;
    }

    @Override
    public String serialize(Object o) {
        if (o == null) {
            return null;
        }
        return new Gson().toJson(o); // ["string"]
    }

    @Override
    public List<String> deserialize(Object o) {
        if (o == null) {
            return null;
        }
        return new Gson().fromJson((String) o, new TypeToken<List<String>>(){}.getType());
    }
}

我今天蛋疼的把这里改了:

    @Override
    public String serialize(Object o) {
        if (o == null) {
            return null;
        }
        return o.toString(); // [string]
    }

Gson对Json的语法检查还是很严格的,toString导致括号内的String少一对引号,所以不能被识别为String类型。

总结

这个Bug之所以难调,是因为数据库里面有残留的错误格式的数据,导致Select一直为Null。我最开始就了怀疑这里,就把代码改回原样子,只是当时没有把数据库删除,导致残留数据无法select,发现Bug依然存在。就把这里排除掉了。真是没想到为啥ActiveAndroid对这里的异常不打Log,其他地方都打了。
最蛋疼的Java编程风格就是一个try-catch把异常都吃了,搞得出问题无从调试。所以宁愿每个函数后面都带throw也不要自己在中间过程的函数中吃了异常。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值