1

I try to use ObjectInputStream and ObjectOutputStream in my Java project but the object I want to send on the network contains other objects than String, int, boolean etc... so it does not work when I try to deserialize it. Do you know other alternatives to send objects that contains other objects?

Here is the class I want to send:

    public class People implements Serializable {
        /**
         * 
         */
        private static final long serialVersionUID = -8308312587789563412L;
        private String ip;
        private Player player;
    
        public People(Player player, String ip) {
            this.player = player;
            this.ip = ip;
        }
    
        public void walk() {
            System.out.printf("%s is walking...\n", player.getName());
        }
    
        public Player getPlayer() {
            return player;
        }
    
        public String getIp() {
            return ip;
        }
    }

Here is the class where I send the object:

    public class ServerMulticast {
    
        final int gamePort = 5000;
    
        private People p1;
        private People p2;
        ServerSocket socketserver;
        Socket socketduserveur;
    
        public ArrayList<People> run(Player player) {
            //Address
            String multiCastAddress = "225.6.7.8";
            final int multiCastPort = 3456;
        
            System.setProperty("java.net.preferIPv4Stack", "true");
        
            try {
                InetAddress group = InetAddress.getByName(multiCastAddress);
                MulticastSocket socket = new MulticastSocket(multiCastPort);
                //String message = pseudo + " is waiting for a second player...";
            
                p1 = new People(player, InetAddress.getLocalHost().getHostAddress());
                ByteArrayOutputStream baos = new ByteArrayOutputStream();
                ObjectOutputStream oos = new ObjectOutputStream(baos);
                oos.writeObject(p1);
                oos.flush();
                byte[] data = baos.toByteArray();
            
                //Send data
                DatagramPacket packet = new DatagramPacket(data, data.length, group, multiCastPort);
                socket.send(packet);
            
                socket.close();
            
                recieveIpAdress();
            
                System.out.printf("%s just joined the game. (ip:%s)\n", p2.getPlayer().getName(), p2.getIp());
            
                //Play
                p2.walk();
                p1.walk();
            
            } catch (Exception e) {
                e.printStackTrace();
            }
        
            ArrayList<People> peoples = new ArrayList<>();
            peoples.add(p1);
            peoples.add(p2);
            return peoples;
        }
    
        private void recieveIpAdress() {
        
            if(p2 == null) {
            
                try {
                    //Créer un socket serveur avec un numéro de port 5000
                    socketserver = new ServerSocket(gamePort);
                    //ecoutes pour une connexion a apporter a ce socket et l'accepte
                    socketduserveur = socketserver.accept();
                
                    // get the input stream from the connected socket
                    InputStream inputStream = socketduserveur.getInputStream();
                    // create a DataInputStream so we can read data from it.
                    ObjectInputStream objectInputStream = new ObjectInputStream(inputStream);
                
                    //read the list of messages from the socket
                    p2 = (People) objectInputStream.readObject();
                
                    socketserver.close();
                    socketduserveur.close();
                
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                } catch (ClassNotFoundException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            
            }
        
        }
    
    }

And here is the class where I recieve it:

    public class ClientMulticast {
    
    private People p1 = null;
    private People p2 = null;

    public ArrayList<People> run(Player player) {
        Scanner sc = new Scanner(System.in);
        String multiCastAddress = "225.6.7.8";
        final int multiCastPort = 3456;
        final int bufferSize = 1024 * 4; // Maximum size of transfer object
        try {           
            p1 = new People(player, InetAddress.getLocalHost().getHostAddress());
        } catch (UnknownHostException e1) {
            // TODO Auto-generated catch block
            e1.printStackTrace();
        }

        System.setProperty("java.net.preferIPv4Stack", "true");

        try {
            InetAddress group = InetAddress.getByName(multiCastAddress);
            MulticastSocket mSocket = new MulticastSocket(multiCastPort);
            mSocket.joinGroup(group);

            boolean bSelectServer = false;
            while (bSelectServer == false) {
                System.out.println("\nWating for players to host games...");
                byte[] buffer = new byte[bufferSize];
                DatagramPacket packet = new DatagramPacket(buffer, bufferSize, group, multiCastPort);
                mSocket.receive(packet); // waits until it recieved a packet
                System.out.println("Player found!");

                // Deserialze object
                ByteArrayInputStream bais = new ByteArrayInputStream(buffer);
                ObjectInputStream ois = new ObjectInputStream(bais);
                
                try {
                    People readObject = (People) ois.readObject();
                    
                    if (readObject instanceof People) {
                        p2 = (People) readObject;
                        System.out.printf("Do you want to connect to %s's game (ip:%s)? (true/false)\n", p2.getPlayer().getName(),
                                p2.getIp());
                        try {
                            bSelectServer = sc.nextBoolean();
                        } catch (Exception e) {
                            System.out.println("ERROR! Your input is not a boolean.");
                        }
                    } else {
                        System.out.println("The received object is not of type People!");
                    }
                } catch (Exception e) {
                    System.out.println("No object could be read from the received UDP datagram.");
                }
            }

            mSocket.close();

            sendIpAdress();

            System.out.printf("You just joined %s's game\n", p2.getPlayer().getName());

            // Play
            p1.walk();
            p2.walk();

        } catch (Exception e) {
            e.printStackTrace();
        }
        
        ArrayList<People> peoples = new ArrayList<>();
        peoples.add(p1);
        peoples.add(p2);
        return peoples;
    }

    private void sendIpAdress() {
        Socket socketClient;

        try {
            socketClient = new Socket(p2.getIp(), 5000);

            // get the output stream from the socket.
            OutputStream outputStream = socketClient.getOutputStream();
            // create an object output stream from the output stream so we can send an
            // object through it
            ObjectOutputStream objectOutputStream = new ObjectOutputStream(outputStream);

            objectOutputStream.writeObject(p1);
            objectOutputStream.flush();

            // Close socket
            socketClient.close();

        } catch (UnknownHostException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
    }

    }
General Grievance
  • 4,555
  • 31
  • 31
  • 45
Akashiro
  • 11
  • 2
  • 2
    If you have objects in the fields for the object you are serializing (through `Serializable` or json mapping or otherwise), those objects will also need to be serializable. So in serializing `People`, you will also need `Player` to be serializable (or `transitive` to exclude it). – Rogue Oct 14 '22 at 14:23
  • All my sub-classes are already Serialize so I don't think that this is the problem unfortunetly – Akashiro Oct 14 '22 at 14:30
  • 1
    Spending time on Java serialization is a waste of time. It is something that in 1995 made sense, but now there are better, multi-language multi-platform serialization languages like XML and JSON – ControlAltDel Oct 14 '22 at 14:30
  • 2
    Please explain how exactly it doesn't work. Do you get some error? – talex Oct 14 '22 at 14:33
  • With the code up ther, i get the error : java.net.SocketException: The message is larger than the maximum supported by the underlying transport: no further information. But if I change data.lenght in the DatagramPacket of the Server class to 4096, then it just shows "No object could be read from the received UDP datagram." in the console (this is the catch message from the client class) – Akashiro Oct 14 '22 at 14:37
  • That should probably be ```ByteArrayInputStream bais = new ByteArrayInputStream(packet.getData());``` And you want ```e.printStackTrace());``` - never restrict the amount of error/debug information – g00se Oct 14 '22 at 15:24
  • Share your `Player` class. – shmosel Oct 14 '22 at 18:10
  • Split up your problem. Test the serialise and load independently of transport code. Then test send and receive with fixed data eg `"helloworld".repeat(nnn).getBytes()` with nnn increasing each time and post the part that actually fails – DuncG Oct 14 '22 at 20:59

1 Answers1

0

The problem was that I was doing a recursive call in one of my sub-classes (instantiate a CLASS with a List of CLASS). Thanks for your answers it helped me a lot !

Akashiro
  • 11
  • 2
  • If this solve your problem, and you don't get any better answer from someone else, you should accept your own answer! – Lii Oct 19 '22 at 07:25