从流中读取对象时的Java ClassNotFoundException

时间:2012-05-07 09:14:13

标签: java serialization objectinputstream

从ObjectInputStream读取Object时,我收到ClassNotFoundException。正在发送的对象是子类化“WorkUnit”,读取代码具有该引用。似乎接收端抱怨,因为它不知道具体的实现。当我只引用对象的超类时,为什么会关心它:接收端的“WorkUnit”?

从Stream中读取的代码:

private Object readObject() {
    Object object = null;
    try {
        object = objectIn.readObject();
    } catch (SocketException | EOFException e) {
        // Socket was forcedly closed. Probably means client was
        // disconnected
        System.out.println("[NetworkHandler] SOCKET CLOSED");
        shouldContinue = false;
        if (!isClient)
            server.clientDisconnected(clientID);
    } catch (ClassNotFoundException | IOException e) {
        // If shouldContinue is true, we haven't said that we want to close
        // the connection
        if (shouldContinue) {
            e.printStackTrace();
            System.err
                    .println("[NetworkHandler] Error: Couldn't read object correctly");
        }
    }
    return object;
}

工作单位实施:

import java.util.LinkedList;
import java.util.List;

import Application.WorkUnit;


public class WorkUnitImplementation extends WorkUnit<Integer, Integer> {

private static final int INPUT_LENGTH = 1000;

public WorkUnitImplementation() {
    super();

    setInputLength(INPUT_LENGTH);
}

@Override
public Integer doWork(Integer input) {
    wait(50);
    return (input % 2 == 1) ? input : null;
}

@Override
public List<Integer> inputFactory(int begin, int end) {
    List<Integer> result = new LinkedList<>();
    for (int i = begin; i < end; i++) {
        result.add(i);
    }
    return result;
}

private void wait(int time) {
    try {
        Thread.sleep(time);
    } catch (Exception e) {

    }
}
}

发送工作单位的代码:

    public void uploadWorkUnit(WorkUnit workUnit) {
    try {
        objectOut.writeObject(new UploadWorkUnit(workUnit));
        objectOut.flush();
        System.out.println("[NetworkHandler] Uploaded workUnit");
    } catch (IOException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}

异常追踪:

java.lang.ClassNotFoundException: WorkUnitImplementation
at java.net.URLClassLoader$1.run(URLClassLoader.java:366)
at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
at java.lang.ClassLoader.loadClass(ClassLoader.java:423)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)
at java.lang.ClassLoader.loadClass(ClassLoader.java:356)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:264)
at java.io.ObjectInputStream.resolveClass(ObjectInputStream.java:622)
at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1593)
at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1514)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1750)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1347)
at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:1964)
at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:1888)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:1771)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1347)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:369)
at Networking.NetworkHandler.readObject(NetworkHandler.java:188)
at Networking.NetworkHandler.run(NetworkHandler.java:90)
at java.lang.Thread.run(Thread.java:722)

[NetworkHandler]错误:无法正确读取对象

4 个答案:

答案 0 :(得分:2)

  

接收端似乎在抱怨,因为它不知道具体的实现。当我只引用对象的超类时,为什么会关心它:接收端的“WorkUnit”?

这是因为流包含实现类'字段。

来自ObjectOutputStream javadoc:

  

对象的默认序列化机制会写入对象的类,类签名以及所有非瞬态和非静态字段的值。

反序列化过程读取流以发现应自动重构的类。它尝试创建该类的新实例,以便它可以使用流中包含的字段填充它。

如果接收端没有与编写的相同的类,它将无效 - 您将获得ClassNotFoundException

(也就是说,被序列化的类可以使用writeReplace(),但这可能超出了这个问题的范围。)

答案 1 :(得分:2)

我有时会遇到同样的问题,我通过将要通过网络发送的类放在它自己的包中(在发送端和接收端)来解决它,然后将其导入到其中的类中被发送或接收。请注意,两端的包结构应该相同。

答案 2 :(得分:0)

作为猜测,您在不同的计算机上运行发送方和接收方。您是否检查过每个字段上是否有相同版本的此类?

答案 3 :(得分:0)

是的,我遇到了同样的问题。我通过在同一个包上使用相同的序列化类来解决它。将ObjectOutputStream和ObjectInputStream函数放在同一个包中并执行输出,然后单独输入或调用。