3

In both client and server classes, I have an exact same inner class called Data. This Data object is being sent from the server using:

ObjectOutputStream output= new ObjectOutputStream(socket.getOutputStream());
output.writeObject(d);

(where d is a Data object)

This object is received on the client side and cast to a Data object:

ObjectInputStream input = new ObjectInputStream(socket.getInputStream());
Object receiveObject = input.readObject();
if (receiveObject instanceof Data){
    Data receiveData = (Data) receiveObject;
    // some code here... 
}

I'm getting a java.lang.ClassNotFoundException: TCPServer$Data on this line Object receiveObject = input.readObject();

My guess is that it's trying to to look for the Data class in the Server side and can't find it, but I'm not sure... How do I fix this?

Dao Lam
  • 2,837
  • 11
  • 38
  • 44
  • 2
    It seems you have duplicate code of the Data inner class. At client end, what class has the inner class Data? Do you have TCPServer class at client end too? – devang Jul 31 '12 at 17:36
  • 1
    Show us the imports of the client class containing the above code. – JB Nizet Jul 31 '12 at 17:38
  • Data is an inner class that is in both TCPServer.java and TCPClient.java. The exception is occuring in the TCPClient.java – Dao Lam Jul 31 '12 at 17:42
  • 2
    I think if it's an inner class in both TCPServer and TCPClient, that won't work. It would have to be it's own class, or you'd need the TCPServer$Data class available on the client. – Alper Akture Jul 31 '12 at 17:47
  • Thanks! I'm trying that right now! :) – Dao Lam Jul 31 '12 at 18:11

2 Answers2

8

What you were trying to do is something along the lines of the following:

class TCPServer {
    /* some code */

    class Data {

    }
}

class TCPClient {
    /* some code */

    class Data {

    }
}

Then you are serializing a TCPServer$Data and trying to unserialize it as a TCPClient$Data. Instead you are going to want to be doing this:

class TCPServer {
    /* some code */

}

class TCPClient {
    /* some code */

}

class Data {
    /* some code */

}

Then make sure the Data class is available to both the client and the server programs.

Jyro117
  • 4,519
  • 24
  • 29
  • Thank you. I'm assuming the Data classes on both side have to have the same package name as well? – Dao Lam Jul 31 '12 at 18:15
  • 2
    Yes, they need to be the exact same class. "com.test.Data" is not the same as "com.abc.Data" even if the code inside both files are the same. – Jyro117 Jul 31 '12 at 18:18
  • @Jyro117 Your one liner just ended my 2 hour search for an answer, thank you! – basickarl Oct 27 '13 at 07:02
  • I was actually just trying to figure out why ClassNotFoundException even existed, since you have to downcast to the correct type after deserialization. Knowing what you've explained here makes that behavior make sense! I was unaware that the entire hierarchy must match -- but that makes a lot of good sense now, thinking about it. It's necessary to really ensure the deserialized object is truly the same class. – apraetor May 10 '17 at 03:40
3

When you use some class in two different JVMs, and you are marshalling/unmarshalling the class then the class should be exported to a common library and shared between both server and client. Having different class wont work any time.

What you are trying to do is marshall TCPServer$Data and unmarshall as TCPClient$Data. That is incompatible.

devang
  • 5,376
  • 7
  • 34
  • 49