Java Deserializing ArrayList in a loop

Question:

Guys, good afternoon!

I am a beginner and am doing the following assignment. You need to build a client / server application where clients send objects to the server periodically. the server adds these values ​​to the ArrayList and periodically sends them to clients. The problem is that not the whole ArrayList is read on the client side. but only the first few elements are read. Help me to understand. Codes and information output below.

SERVER PART

             package sockets;

import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.PrintWriter;
import java.net.ServerSocket;
import java.net.Socket;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.ArrayList;
import java.util.Iterator;

import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;


public class ServerSocketProg extends JFrame implements Runnable {

    /**
     * 
     */
    private static final long serialVersionUID = 1L;
    ArrayList<String> users;
    private ArrayList<ObjectOutputStream> clientObjectOutputStreams;
    private ArrayList<String> stringArrayList = new ArrayList<String>();
    private ServerSocket serverSock;
    private JTextArea ta_chat;
    private Path path;
    private BufferedWriter fileWriter;

    public ServerSocketProg() {
        initComponents();


        path = Paths.get("ServerLogger.txt");
        try {
            fileWriter = Files.newBufferedWriter(path, 
                    StandardOpenOption.CREATE, StandardOpenOption.TRUNCATE_EXISTING, StandardOpenOption.WRITE);
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    @Override
    public void run() 
    {
        clientObjectOutputStreams = new ArrayList<ObjectOutputStream>();
        users = new ArrayList<String>();  

        try 
        {
            serverSock = new ServerSocket(2222);
            while (true) 
            {
                Socket clientSock = serverSock.accept();                                        
                ObjectOutputStream objectWriter = new ObjectOutputStream(clientSock.getOutputStream());
                clientObjectOutputStreams.add(objectWriter);

                Thread listenerObject = new Thread(new ClientObjectHandler(clientSock, objectWriter));
                listenerObject.start();
                Thread intervalSender = new Thread(new SendArrayWithInterval());
                intervalSender.start();

                ta_chat.append("Got a connection. \n");
                fileWriter.write("Got a connection. \r\n");
            }
        }
        catch (Exception ex)
        {
            ex.printStackTrace();
            ta_chat.append("Error making a connection. \n");
            try {
                fileWriter.write("Error making a connection. \r\n");
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }   



    class ClientObjectHandler implements Runnable   
    {
           BufferedReader reader;
           Socket sock;
           ObjectOutputStream client;
           ObjectInputStream objectReader;

           public ClientObjectHandler(Socket clientSocket, ObjectOutputStream user) throws IOException 
           {
                client = user;
                try 
                {
                    sock = clientSocket;
                    objectReader = new ObjectInputStream(sock.getInputStream());                
                }
                catch (Exception ex) 
                {
                    ta_chat.append("Unexpected error... \n");                   
                    fileWriter.write(ex.toString());
                }

           }

           @Override
           public void run() 
           {
                String message;    

                try 
                {
                    while ((message = (String) objectReader.readObject()) != null) 
                    {
                        ta_chat.append("Received Object: " + message + "\n");
                        fileWriter.write("Received Object: " + message + "\r\n");
                        stringArrayList.add(message);                                      
                    } 
                 } 
                 catch (Exception ex) 
                 {
                    ta_chat.append("Lost a connection. \n");
                    try {
                        fileWriter.write("Lost a connection\r\n");
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                    clientObjectOutputStreams.remove(client);
                 } 
           } 
        }

    class SendArrayWithInterval implements Runnable{
        @Override
        public void run() {
            while(true){
                try {
                    Thread.sleep(5000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                if(stringArrayList.size()>0){
                    ta_chat.append("Telling everyone Array...\n");                  
                    sendEveryoneObject();
                }
            }
        }
    }

    public void sendEveryoneObject() {
        Iterator<ObjectOutputStream> it = clientObjectOutputStreams.iterator();

        while (it.hasNext()) 
        {
            try 
            {
                ObjectOutputStream outputWriter = (ObjectOutputStream) it.next();


                outputWriter.writeObject(stringArrayList);

                outputWriter.flush();

                ta_chat.append("Sending: " + stringArrayList.toString() + "\n");        
                ta_chat.setCaretPosition(ta_chat.getDocument().getLength());
                fileWriter.write("Sending: " + stringArrayList.toString() + "\r\n");

            } 
            catch (Exception ex) 
            {
                ex.printStackTrace();
                ta_chat.append("Error telling everyone. \n");
                try {
                    fileWriter.write("Error telling everyone. \r\n");
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }




    }


    private void initComponents() {
        JScrollPane jScrollPane1 = new javax.swing.JScrollPane();
        ta_chat = new javax.swing.JTextArea(40, 50);        
        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
        setTitle("Chat - Server's frame");
        setName("server");        

        jScrollPane1.add(ta_chat);
        jScrollPane1.setViewportView(ta_chat);
        add(jScrollPane1);

        addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent arg0) {
                try {
                    fileWriter.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }); 

        setSize(400, 600);
        setVisible(true);
        pack();
    }



    public static void main(String[] args) {        
        Thread starter = new Thread(new ServerSocketProg());
        starter.start();            
    }
}

CLIENT SECTION:

package sockets;

import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.net.Socket;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.ArrayList;

import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;


public class ClientsSocketsProgram extends JFrame implements Runnable {
    /**
     * 
     */
    private static final long serialVersionUID = 1L;
    private String address = "localhost";
    private int port = 2222;
    private Boolean isConnected = false;  
    private static int instance = 0;
    private Socket sock;
    private ObjectOutputStream objectWriter;
    private ObjectInputStream objectReader; 
    private JTextArea ta_chat;
    private Path path;

    private int incrementerToSend = 0;

    public ClientsSocketsProgram() {

        initComponentsClientFrame();
        connectToServer();       

        Thread incomeReader = new Thread(new IncomingReader());
        incomeReader.start();
    }   

    class IncomingReader implements Runnable
    {
        ArrayList<String> inputArrayList;// = new ArrayList<String>();
        @Override
        public void run() 
        {
            ArrayList<String> here = new ArrayList<String>();


            try 
            {
                while( true  ){

                    here =(ArrayList<String>) objectReader.readObject();                    

                    ta_chat.append("Object received: " + here.toString() + "\n "); 
                    ta_chat.setCaretPosition(ta_chat.getDocument().getLength());              
                }
           }catch(Exception ex) {

               ex.printStackTrace();
           }
        }



    }

    @Override
    public void run() { 
        while(isConnected){
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            ta_chat.append("Sending " + incrementerToSend + "\n");

            sendObject(" " + incrementerToSend);
            ++incrementerToSend;
        }

    }




    private void initComponentsClientFrame() {

        JScrollPane jScrollPane = new javax.swing.JScrollPane();
        ta_chat = new javax.swing.JTextArea(20, 30);

        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setTitle(" Chat - Client's frame");
        setName("client"); 


        jScrollPane.add( ta_chat );
        jScrollPane.setViewportView(ta_chat);
        add(jScrollPane);

        addWindowListener(new WindowAdapter() {
            @Override
            public void windowClosing(WindowEvent arg0) {
                closeConnections();
            }
        }); 

        setSize(400, 600);
        setVisible(true);
        pack();
    }



    private void connectToServer() {
        if (!isConnected) 
        {
            try 
            {
                sock = new Socket(address, port);                
                objectReader = new ObjectInputStream(sock.getInputStream());
                objectWriter = new ObjectOutputStream(sock.getOutputStream()); 
                isConnected = true; 
            } 
            catch (Exception ex) 
            {
                ta_chat.append("Cannot Connect! Try Again. \n");

            }

        } else if (isConnected) 
        {
            ta_chat.append("You are already connected. \n");

        }
    }

    private void sendObject(String text) {

        try  {
            objectWriter.writeObject(text);
            objectWriter.flush();           
        } catch (Exception ex) {
            ta_chat.append("Message was not sent. \n");


            ex.printStackTrace();
        }

    }

    private void closeConnections(){
        if(isConnected){
            try{
                objectWriter.close();
                objectReader.close();
                sock.close();

                isConnected = false;
            }catch(Exception e){
                e.printStackTrace();
            }
        }       
    }





    public static void main(String args[]) 
    {
        Thread thread = new Thread(new ClientsSocketsProgram());
        thread.start();

    }


}

WITHDRAWAL OF THE SERVER PART (2 CLIENTS STARTED):

         Got a connection. 
Received Object:  0
Received Object:  1
Telling everyone Array...
Sending: [ 0,  1]
Received Object:  2
Got a connection. 
Received Object:  3
Received Object:  0
Received Object:  4
Received Object:  1
Telling everyone Array...
Sending: [ 0,  1,  2,  3,  0,  4,  1]
Sending: [ 0,  1,  2,  3,  0,  4,  1]
Telling everyone Array...
Sending: [ 0,  1,  2,  3,  0,  4,  1]
Sending: [ 0,  1,  2,  3,  0,  4,  1]
Received Object:  5
Received Object:  2
Received Object:  6
Received Object:  3
Telling everyone Array...
Sending: [ 0,  1,  2,  3,  0,  4,  1,  5,  2,  6,  3]
Sending: [ 0,  1,  2,  3,  0,  4,  1,  5,  2,  6,  3]

CONCLUSION CLIENT SECTION:

Sending 0
Sending 1
Object received: [ 0,  1]
 Sending 2
Sending 3
Sending 4
Object received: [ 0,  1]
 Object received: [ 0,  1]
 Sending 5
Sending 6
Object received: [ 0,  1]
 Sending 7
Object received: [ 0,  1]
 Sending 8
Sending 9
Object received: [ 0,  1]
 Object received: [ 0,  1]
 Sending 10
Sending 11
Object received: [ 0,  1]
 Sending 12

Answer:

This is because you are passing the same ArrayList object every time. ObjectInputStream / ObjectOutputStream allow you to pass an object along with all its fields, which can contain references to other objects, which can also refer to someone. Since there can be multiple references to the same object, during deserialization these references are restored instead of creating multiple copies. Those. writeObject sees that it has already written this object, and puts a link into the stream, and readObject returns you a link to a previously deserialized object.

To avoid this, you can use ObjectOutputStream.writeUnshared so that the main object is considered unique. You can also call ObjectOutputStream.reset() after recording so that subsequent records do not take into account previously serialized objects, and write them in a new way, and not as references.

It might be worth creating a new ArrayList in sendEveryoneObject and sendEveryoneObject it.


Note that you are very loose with multithreading. ArrayList not a thread-safe collection, and does not provide any guarantees if modified at the same time (when two clients sent you a message, for example). You need to either provide thread safety yourself via synchronized or Lock from java.util.concurrent , use Collections.synchronizedList (note the way of using the iterator in the method documentation), or use some kind of collection from java.util.concurrent ( CopyOnWriteArrayList is not good for you. will do because there are many modifications, but one of the queues may be suitable for storing messages). In the last two cases, it is worth copying the data before sending it to the clients into a locally created list.

When accessing Swing components, use SwingUtilities.invokeLater because all calls must be made from the Event Dispatch Thread.

There is no need to create a new new Thread(new SendArrayWithInterval()) every time the client connects, so your server new Thread(new SendArrayWithInterval()) duplicates.

Scroll to Top