1

I'm sending a POJO through a socket in Java using ObjectOutputStream the POJO is below

import java.io.Serializable;

public class Game implements Serializable {
    private static final long serialVersionUID = 4367518221873521320L;
    private int[][] data = new int[3][3];

    Game() {
        for (int x = 0; x < 3; x++) {
            for (int y = 0; y < 3; y++) {
                data[x][y] = 0;
            }
        }
    }

    int[][] getData() {
        return data;
    }

    public void setData(int[][] data) {
        this.data = data;
    }

    void printMatrix() {
        for (int x = 0; x < 3; x++) {
            for (int y = 0; y < 3; y++) {
                System.out.print(data[x][y] + " ");
            }
            System.out.println();
        }
    }
}

I have a Server and Client classes, the idea is to create an instance of the Game class in the server and send it to the client, then perform changes in the data variable and send it again back and forth between the Server and the Client.

The object is being sent but its content is not the expected.

Server Output

Waiting
Connected server
0 0 0 
0 0 0 
0 0 0 
Writing
0 0 0 
0 1 0 
0 0 0 

Expected Output (Client)

Connecting...
Connected client
Reading
0 0 0 
0 0 0 
0 0 0 
Reading
0 0 0 
0 1 0 
0 0 0

Actual Output (Client)

Connecting...
Connected client
Reading
0 0 0 
0 0 0 
0 0 0 
Reading
0 0 0 
0 0 0 #<-- there is no 1
0 0 0

Server class

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.ServerSocket;
import java.net.Socket;

public class Server {
    void start(int port) throws IOException {
        ServerSocket serverSocket = new ServerSocket(port);
        System.out.println("Waiting");
        Socket socket = serverSocket.accept();
        System.out.println("Connected server");

        Game game = new Game();
        game.printMatrix();

        ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());
        ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());

        System.out.println("Writing");
        oos.writeObject(game);

        game.getData()[1][1] = 1;
        game.printMatrix();
        oos.writeObject(game);
    }

    public static void main(String[] args) throws Exception {
        new Server().start(8082);
    }
}

Client class

import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;

public class Client {
    public void connect(String host, int port) throws Exception {
        System.out.println("Connecting...");
        Socket socket = new Socket(host, port);
        System.out.println("Connected client");

        ObjectInputStream ois = new ObjectInputStream(socket.getInputStream());
        ObjectOutputStream oos = new ObjectOutputStream(socket.getOutputStream());

        System.out.println("Reading");
        Game game1 = (Game) ois.readObject();
        game1.printMatrix();
        System.out.println("Reading");
        Game game2 = (Game) ois.readObject();
        game2.printMatrix();

    }

    public static void main(String[] args) throws Exception {
        new Client().connect("localhost", 8082);
    }
}

Question

Why if the matrix is being modified in the server when it is sent to the client the client receives the non-modified matrix?

Thanks

1 Answers1

1

Java Serialization can handle cycles all sorts of object graph. It does this by sending back references instead of serialising the object twice.

The second time you are sending the object, you are just sending a reference. You need to either call ObjectOutputStream.reset the stream, close that stream replacing with another or, best, use immutable value objects. Or either of the first two and last of these - in order to be able to use the back reference the ObjectOutputStream keeps a reference to all objects sent, and ObjectInputStream likewise for all objects received.

(You can use ObjectOutputStream.writeUnshared but that gets even more confusing because the component objects will be shared.)

Stndard warning: Don't use Java Serialization.

Tom Hawtin - tackline
  • 145,806
  • 30
  • 211
  • 305
  • so, basically after sending the object I have to call reset() and in the client, after I read I have to reset too, right? thanks by the advice – Frederick Álvarez Dec 11 '18 at 00:10
  • That's one way of handling it. It's more usual to use another `ObjectOutputStream` although that means sending the class descriptor data again, which probably isn't so much of a problem. – Tom Hawtin - tackline Dec 11 '18 at 00:11