Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

(java) ObjectInputStream deserializing wrong version of object [duplicate]

I'm just learning networking from a java book, so I'm a bit of a noob. I couldn't find this problem in the book or online so I decided to ask the internet.

The book says to use the ObjectOutputStream and ObjectInputStream to send and receive objects to different consoles.

Now, I'm able to successfully receive the objects I send-- but only once. When I send different objects: random strings and Integers and nameless instances, the console has all the correct fields. But when I send an instance of an object, change the value of one of the instance's fields, and resend the object, then the inpustream loads the original instance's values.

So, say for example, I had an instance of a class with a public int "var" equal to 1. If I send the instance of this class, the client receives it and correctly reports that var = 1. However, if I change var to 2 (in the same instance) and resend it, the client will finish calling the read() method (so it must have received the new object!), but it will report var as being 1. If I send the instance to a different client who has not yet received the instance, it will correctly report var as 2, and it will continue to report it as 2 even if I change var.

The fact that the client reads the correct version of the instance if it hasn't received it before must mean that the object is being properly sent through the outputstream; for some reason the inputstream just isn't working. It's almost like it sees that its the same object so it assumes that it has the same values without checking. Why does this happen and how can I fix it?

Sorry if I'm asking something stupid- the book doesn't explain how serialization and sockets work, just how to use them, so I could very well be fundamentally confused about how to use them. Thank you!

Simple code that I wrote to test the problem:

Server: (has a timer action to keep sending updated objects)

    public void actionPerformed(ActionEvent e)
{
    object.var++;
            output.write(object);
            output.flush();
            System.out.println(object.var);
}

Client

    public void run()
{
    while(true)
            {
                   Test t = (Test)input.readObject();
                   System.out.println(t.var);
            }
    }

When these programs run the output for the Server class is 1,2,3,4... increasing infinitely, while the Client's output is just 1,1,1,1,1,1,1,etc.

Thank you for taking the time to read this. Sorry if I'm just being dumb, I'm new to this stuff.

EDIT: Sorry, the the read() was a mistype (i manually typed the code because i couldn't eget the formatting right), I meant input.readObject()

like image 546
superzipzop Avatar asked Jun 15 '11 02:06

superzipzop


2 Answers

The reason is that ObjectOutputStream caches object references and writes back-references to the stream if the same object is written twice. That means when you call write the second time the stream doesn't actually write a new copy of the object, it just inserts a reference to the object that it's already written.

You can prevent this by calling ObjectOutputStream.reset between calls to write. That tells the stream to discard any cached references.

This behaviour seems strange but it's actually necessary to prevent infinite loops if you try to serialize an object graph that has circular references (i.e. write object A that refers to object B that in turn refers back to object A).

like image 178
Cameron Skinner Avatar answered Nov 09 '22 08:11

Cameron Skinner


Are you using read() or readObject() from ObjectInputStream? If you're using read() then you're just getting a single byte of data. Try converting the client

public void run()
{
  while(true)
  { 
    Test t = (Test)input.readObject();
    System.out.println(t.var);
  }
}

EDIT: should've been input.readObject();

like image 22
Suroot Avatar answered Nov 09 '22 09:11

Suroot