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

前端之家收集整理的这篇文章主要介绍了最难调的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也不要自己在中间过程的函数中吃了异常。

猜你在找的Sqlite相关文章