Java ClassNotFoundException when reading object from a stream

雨燕双飞 提交于 2019-12-23 22:07:06

问题


I am getting a ClassNotFoundException when reading an Object from an ObjectInputStream. The object that is being sent is subclassing "WorkUnit" which the reading code has a reference to. It would seem that the receiving end is complaining because it doesn't know about the specific implementation. Why would it care about that when I'm only referencing the object's superclass: "WorkUnit" on the side that is receiving?

Code to read from 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;
}

Work Unit Implementation:

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) {

    }
}
}

Code to send Work Unit:

    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();
    }
}

Exception Trace:

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] Error: Couldn't read object correctly


回答1:


It would seem that the receiving end is complaining because it doesn't know about the specific implementation. Why would it care about that when I'm only referencing the object's superclass: "WorkUnit" on the side that is receiving?

It's because the stream consists of the implementation class' fields.

From ObjectOutputStream javadoc:

The default serialization mechanism for an object writes the class of the object, the class signature, and the values of all non-transient and non-static fields.

The deserialisation process reads the stream to discover the class that should be automagically reconstituted. It tries to create a new instance of that class so that it can then populate it with the fields that are contained in the stream.

If the receiving end doesn't have the same class that was written, it won't work -- you'll get a ClassNotFoundException.

(That said, the class being serialised could use writeReplace(), but that's probably beyond the scope of this question).




回答2:


I had the same problem sometimes and I solved it by putting the class that's to be sent over the network in a package of its own (both on the sending end and the receiving end) and then import it into the class where its being sent or received. Note that the package structure should be the same on both ends.




回答3:


As a guess, you are running the sender and the receiver on different machines. Did you check that they have the same version of this class on each field?




回答4:


Yea, I had the same problem. I have solved it by using the same serialized class on the same package. Put ObjectOutputStream and ObjectInputStream function in the same package and execute output then input or call separately.



来源:https://stackoverflow.com/questions/10479481/java-classnotfoundexception-when-reading-object-from-a-stream

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!