`
ywu
  • 浏览: 452752 次
  • 性别: Icon_minigender_1
  • 来自: 无锡
社区版块
存档分类
最新评论

java.io.NotSerializableException: java.util.RandomAccessSubList

阅读更多

本系列博客是在日常开发中遇到的各类异常、问题的分析总结。

 

今天在测试功能的时候,控制台抛出了java.io.NotSerializableException: java.util.RandomAccessSubList异常,具体的堆栈信息如下:
java.io.NotSerializableException: java.util.RandomAccessSubList
at java.io.ObjectOutputStream.writeObject0(Unknown Source)
at java.io.ObjectOutputStream.writeObject(Unknown Source)
at com.ibm.commerce.multichannel.dao.TaskDao.objectToBytes(TaskDao.java:301)
at com.ibm.commerce.multichannel.dao.TaskDao.createBatchTask(TaskDao.java:147)
at com.ibm.commerce.multichannel.flow.task.inventory.BatchUpdateInventoryTask.doTask(BatchUpdateInventoryTask.java:98)
at com.ibm.commerce.multichannel.flow.task.Task.run(Task.java:89)
at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(Unknown Source)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
at java.lang.Thread.run(Unknown Source)

简要介绍下代码中的场景:
在TaskDao.java:301行,在将java应用中的对象保存到数据库中时,使用了ObjectOutputStream将对象转换为字节数组,然后保存到数据库中:
ByteArrayOutputStream baos = null;
ObjectOutputStream oos = null;
try {
    baos = new ByteArrayOutputStream();
    oos = new ObjectOutputStream(baos);
    oos.writeObject(obj);
    return baos.toByteArray();
} catch (Exception e) {
    ...
}

我们再来看下调用TaskDao的地方的代码:
InventoryList inventoryList = (InventoryList)this.getData();
List<SKUInventory> skus = inventoryList.getList();
List<Task> tasks=new ArrayList<Task>();
...
if(skus.size()>0 && (this.getChannelId() == CHANNEL_ID_YHD)){
    int totalBatch = ((skus.size() % BATCH_SIZE) == 0 ? (skus.size() / BATCH_SIZE) : (skus.size() / BATCH_SIZE + 1));
    ...
    if(i == (totalBatch-1)){
        batchInventoryTask.setData(skus.subList(BATCH_SIZE * i, skus.size()));
    }else{
        batchInventoryTask.setData(skus.subList(BATCH_SIZE * i, BATCH_SIZE * (i + 1)));
    }
    ...
    tasks.add(batchInventoryTask);
}
taskDao.createBatchTask(tasks);

这里省略了不相干的代码,batchInventoryTask.setData中的参数就是TaskDao中要转成字节数组的Object,可以看出,这个Object其实是List的subList方法返回的结果,这边List<SKUInventory> skus的真实类型是ArrayList。

我们来分析下异常:
java.io.NotSerializableException: java.util.RandomAccessSubList,凭经验猜测,可能是序列化相关问题,看下ObjectOutputStream的介绍,JDK1.6 API帮助文档.CHM中对其的解释是这样的(片段):
...
ObjectOutputStream 将 Java 对象的基本数据类型和图形写入 OutputStream。可以使用 ObjectInputStream 读取(重构)对象。通过在流中使用文件可以实现对象的持久存储。如果流是网络套接字流,则可以在另一台主机上或另一个进程中重构对象。
只能将支持 java.io.Serializable 接口的对象写入流中。每个 serializable 对象的类都被编码,编码内容包括类名和类签名、对象的字段值和数组值,以及从初始对象中引用的其他所有对象的闭包。

即能被ObjectOutputStream 操作的对象必须实现了 java.io.Serializable接口,很有可能代码中转换的Object没有实现 java.io.Serializable接口,而这个Object的实际类型是List的subList方法返回的结果。

再来分析下List的subList方法。subList方法签名如下:
List<E> subList(int fromIndex, int toIndex);
应用中List的实现使用的是ArrayList,我们看下ArrayList中subList方法的实现;
ArrayList中并没有subList方法的实现,看下ArrayList的定义
public class ArrayList<E> extends AbstractList<E>
        implements List<E>, RandomAccess, Cloneable, java.io.Serializable
其继承了AbstractList,以下代码是AbstractList中subList方法的实现:
public List<E> subList(int fromIndex, int toIndex) {
    return (this instanceof RandomAccess ?
            new RandomAccessSubList<E>(this, fromIndex, toIndex) :
            new SubList<E>(this, fromIndex, toIndex));
}
从ArrayList的定义中看到,其实现了RandomAccess接口,因此this instanceof RandomAccess 返回true,subList方法返回的是new RandomAccessSubList<E>(this, fromIndex, toIndex)

再来看下RandomAccessSubList的定义:
class RandomAccessSubList<E> extends SubList<E> implements RandomAccess {
    ...
}
其继承了SubList,实现了RandomAccess 接口,以下是他的继承结构


而RandomAccess 是一个空接口,其定义如下
public interface RandomAccess {
}

再来看下SubList定义:
class SubList<E> extends AbstractList<E> {
}
其继承了AbstractList

AbstractList定义如下:
public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E> {
}

List接口定义如下:
public interface List<E> extends Collection<E> {
}

AbstractCollection定义如下:
public abstract class AbstractCollection<E> implements Collection<E> {
}

最终汇聚到Collection接口,Collection接口定义如下:
public interface Collection<E> extends Iterable<E> {
}

再来看下Iterable定义:
public interface Iterable<T> {
}

废了这么多劲看了这么多接口、实现类定义,只想说明一件事,就是RandomAccessSubList没有实现java.io.Serializable接口,因此在TaskDao中将其转换为字节数组时才会抛出java.io.NotSerializableException: java.util.RandomAccessSubList异常。

  • 大小: 6.9 KB
分享到:
评论

相关推荐

Global site tag (gtag.js) - Google Analytics