3

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

2
  • Post your code. If you don't, then the answer is "your guess is as good as mine". Commented May 7, 2012 at 9:16
  • Please post your code, and the exception trace you receive. Commented May 7, 2012 at 9:18

4 Answers 4

2

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

Sign up to request clarification or add additional context in comments.

11 Comments

On the sending side, I'm already reading the .java and compiling it. Do you think I could hack together a solution by sending the .java and compiling it on the receiving end?
Or, could I override the writeReplace() and return the super class?
@rynojvr: The receiving end needs to be able to deserialise it. So even if you used writeReplace() to change what was written to the stream, the object at the other end needs to be able to read the fields from the stream. In other words, your superclass on the client side would have to have a custom readObject() method that knew how to pick apart the fields.
@rynojvr: why do you have this 'atypical' arrangement?
I'm making a distributed processing mesh for a school project. The client is supposed to be able to create their own WorkUnit that they want the mesh to work on.
|
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.

Comments

0

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?

1 Comment

They're on the same machine now, but that's only for development purposes. The goal was to have someone write their own WorkUnit and then send it off to be worked on.
0

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.