Problema de envio de objeto via Socket - Quase resolvido, falta pouco

Olá !

Estou desenvolvendo uma aplicação Client-Server, onde o servidor mantem uma coleção de objetos (Funcionários) e a distribui esta coleção atualizada para todos os clientes toda vez que algum cliente se conecta no servidor.
Porém meu problema está em enviar a coleção que na verdade é um ArrayList. Se eu não atualizar a List e enviar do jeito que ela foi montada vai certinho, mas eu preciso alterar o status de um Funcionário para depois repassar a List atualizada, quando faço esta atualização gera a seguinte Exception: java.io.NotSerializableException: java.io.PrintStream.

Segue abaixo o trecho de código com problema:


            OutputStream out = conexao.getOutputStream();
            ObjectOutputStream oout=new ObjectOutputStream(out);

            List envio = new ArrayList();
            for (Iterator I = usuarios.iterator(); I.hasNext();){
                Funcionario func = ((Funcionario) I.next());

                if ((func.getUserName().substring(16)).equals(meuNome)){
                    func.setID(saida);
                    func.setStatus("Presente");
                    System.out.println((func.getUserName().substring(16))+" --> Funcionário logado");
                    System.out.println(func.getStatus());
                    System.out.println(func.getID());
                }
                envio.add(func);
            }

            oout.writeObject(envio);
            oout.flush();

Se eu comentar as linhas:

      func.setID(saida);
      func.setStatus("Presente");

e enviar o objeto usuarios, vai certinho porém o objeto usuarios não está atualizado.

Como resolver?

Agradeço antecipadamente.

Verifique as variáveis de instância da classe que não está conseguindo ser serializada (por exemplo, deve ser Funcionario) e veja se alguma delas é uma PrintStream. Se for, então use o modificador “transient” nessa variável de instância.

Olá entanglement ,
Muito obrigado pela ajuda, problema resolvido. Era uma variável dentro da classe Funcionario realmente que não possuia esse modificador transient, não conhecia esse modificador, pelo que li a respeito ele não permite que a variavel seja enviada pela rede e realmente nesse caso a variável só é utilizada no lado do servidor.

Mais uma vez Obrigado.

Cara, tem como colocar o codigo ae pra eu ver como ficou com o “transient”?

E se deu certo, adicionar [RESOLVIDO] no titulo…

Valeu, abraco!

Fala kenneth, então segue parte do código onde tive que colocar o “transient”:

public class Funcionario extends Pessoa implements Serializable{

    public Funcionario(){

    }

    private String departamento;
    private String subGrupo;
    private String cargo;
    private String email;
    private String ramal;
    private String celular;
    private String status;//Presente/Ausente/Reunião na sala/Reunião fora da sala/Desconectado
    private String mensagem;
    private String userName;
    private transient ObjectOutputStream ID;

Depois dessa alteração na classe Funcionário consegui enviar a coleção via socket, porém ainda estou com um probleminha na atualização da coleção, logo mais vou postar o código.

Já estou ficando meio charope de tanto alterar minhas classes e não consigo resolver o problema, vamos ver se alguém consegue me ajudar, a situação é a seguinte:
Eu tenho uma aplicação server que monta uma lista de usuários a partir de uma conexão LDAP, estou armazenando esses usuários em objetos "Funcionarios" e colocados um a um dentro de uma List "ArrayList", depois de montar a coleção a aplicação fica ouvindo uma determinada porta no ServerSocket, quando recebe alguma conexão direciono essa conexão para uma Thread e continuo ouvindo a porta para receber outras conexões, a thread por sua vez percorre a minha coleção de Funcionários até achar o Funcionário que seja igual ao nome do usuário que se conectou quando encontra atualizo alguns campos do objeto Funcionário "que está dentra da coleção"… tipo altero o status dele para presente, depois de alterar o staus, eu envio a coleção agora atualizada para todos os outros usuários que já estavam conectados antes. Por sua vez a aplicação Client se conecta no server, envia o nome do usuário conectado na máquina e fica aguardando o servidor enviar a coleção de Funcionários, quando recebe imprimo tudo na tela. Quando conecto o primeiro usuário fica lindo certinho, mas quando conecto o segundo fica certinho também, mas nesse momento a tela do primeiro usuário é atualizada com a nova lista ou seja deveria aparecer na tela do primeiro usuário que o segundo usuário está "Presente", mas pelo que eu estou entendendo a lista não está atualizando no cliente, segue os códigos:

public class Client extends Thread implements Serializable {

	// Flag que indica quando se deve terminar a execução.
	private static boolean done = false;
    

	//public static void main(String args[]) {
    public Client() {
		try {
			Socket conexao = new Socket("192.000.0.000", 9999);

			PrintStream saida = new PrintStream(conexao.getOutputStream());

			BufferedReader teclado = new BufferedReader(new InputStreamReader(System.in));

			Thread t = new Client(conexao);
			t.start();

			String linha;

			while (true) {
				// ler a linha digitada no teclado
				System.out.print("> ");
				linha = teclado.readLine();

				// antes de enviar, verifica se a conexão não foi fechada
				if (done) {break;}

				// envia para o servidor - Na verdade esse trecho de código só serve para quando enviar uma String vazia o server fecha a conexão.
				saida.println(linha);
			}
		}catch (IOException e) {
			// Caso ocorra alguma excessão de E/S, mostre qual foi.
			System.out.println("IOException: " + e);
		}
	}

// parte que controla a recepção de mensagens deste cliente

	private Socket conexao;

	// construtor que recebe o socket deste cliente
	public Client (Socket s) {
		conexao = s;
	}

	// execução da thread
	public void run() {
		try {
            ObjectInputStream oIn;
            InputStream in;
            in = conexao.getInputStream();
            oIn = new ObjectInputStream(in);

			while (true) {
                try{
                    Object obj = new Object();
                    obj = oIn.readObject();

                    if (obj == null) {

                        System.out.println("Conexão encerrada!");
                        break;
                    }

                    List usr = new ArrayList();
                    
                    if (obj instanceof Resposta) {//Resposta é um objeto que o server retorna quando a conexão é bem sucedida
                        PrintStream saidaTemp = new PrintStream(conexao.getOutputStream());
                        saidaTemp.println(System.getProperty("user.name"));//Envia o nome do usuário
                        System.out.println("CONECTADO");
                    }else if(obj instanceof List) {//Aqui recebo a Lista de Funcionários
                        usr = (ArrayList) obj;
                        System.out.println("Recebeu a coleção");
                        for (Iterator I = usr.iterator(); I.hasNext();){
                            Funcionario func = ((Funcionario) I.next());
                            System.out.println((func.getUserName().substring(16)));
                            System.out.println(func.getStatus());//O problema é que este campo não é atualizado, traz sempre o mesmo valor, mas lá no server está sendo enviado corretamente
                        }
                    }
                }catch(ClassNotFoundException cnfe){
              		System.out.println("not found");
         		}
			}
		}catch (IOException e) {
			// caso ocorra alguma exceção de E/S, mostre qual foi.
            done = true;
			System.out.println("IOException: " + e);
		}

		// sinaliza para o main que a conexão encerrou.
		done = true;
	}
}

Agora o código do Server:

public class Main extends Thread{


    

    // socket deste cliente
    private Socket conexao;

    private static Vector clientes;

    // nome deste cliente
    private String meuNome;

    private static List usuarios = new ArrayList();

    public static void main(String[] args) {

        try{


            montaLista();

            // criando um socket que fica escutando a porta 9999.
            ServerSocket s = new ServerSocket(9999);

            //Monta serviço
            System.out.println("Montando serviço de escuta.");

            try {
                // Loop principal.
                while (true) {
                    // aguarda algum cliente se conectar. A execução do
                    // servidor fica bloqueada na chamada do método accept da
                    // classe ServerSocket. Quando algum cliente se conectar
                    // ao servidor, o método desbloqueia e retorna com um
                    // objeto da classe Socket, que é porta da comunicação.
                    System.out.print("Esperando alguem se conectar...");
                    Socket conexao = s.accept();
                    System.out.println(" Conectou!");

                    // cria uma nova thread para tratar essa conexão
                    Thread t = new Main(conexao);
                    t.start();
                    // voltando ao loop, esperando mais alguém se conectar.
                }
            }catch (IOException e) {
                // caso ocorra alguma excessão de E/S, mostre qual foi.
                System.out.println("IOException: " + e);
            }

        }catch (IOException e) {
            // caso ocorra alguma excessão de E/S, mostre qual foi.
            System.out.println("IOException: " + e);
        }

    }//Fim do Main


    public static void montaLista(){
        /**
         * Monta a coleção de Funcionários/usuários
         */
        String grupo;
        String subGrupo;
        grupo = "";
        subGrupo = "";
        System.out.println("Criando instância de conexão com servidor LDAP.");
        DomainCon dominio = new DomainCon();
        System.out.println("Tentativa de conexão com servidor LDAP.");
        dominio.montaColecao();
        System.out.println("Conexão com servidor LDAP bem sucedida.");
        System.out.println("Obtendo coleção de dados.");
        usuarios = dominio.GetColecao(); // Traz a lista de usuários

        clientes = new Vector();


        //Aqui é uma simples conferência dos dados
        for (Iterator I = usuarios.iterator(); I.hasNext();){
            Funcionario func = ((Funcionario) I.next());
            if (!grupo.equals(func.getDepartamento())){
                grupo = func.getDepartamento();
                System.out.println("* "+grupo);
            }
            if (!subGrupo.equals(func.getSubGrupo())){
                subGrupo = func.getSubGrupo();
                System.out.println("** "+subGrupo);
            }
            System.out.println("*** "+func.getNome());
        }
    }

    public Main(Socket s) {

        conexao = s;

    }


    // execução da thread
    public void run() {
        try {
            // objetos que permitem controlar fluxo de comunicação
            BufferedReader entrada = new BufferedReader(new InputStreamReader(conexao.getInputStream()));
            //PrintStream saida = new PrintStream(conexao.getOutputStream());

            OutputStream out = conexao.getOutputStream();
            ObjectOutputStream oout=new ObjectOutputStream(out);

            
            
            //Confirma para o cliente a conexão
            Resposta rsp = new Resposta();
            rsp.setRsposta("CONSYSTEM");
            oout.writeObject((Object)rsp);
	    oout.flush();

            // Aguarda o nome do usuário conectado (nome da conta)
            meuNome = entrada.readLine();


           Funcionario func = new Funcionario();
            for (Iterator I = usuarios.iterator(); I.hasNext();){
                func = ((Funcionario) I.next());

                if ((func.getUserName().substring(16)).equals(meuNome)){
                    func.setID(oout);
                    func.setStatus("Presente");

                    System.out.println((func.getUserName().substring(16))+" --> Funcionário logado");
                    System.out.println(func.getStatus());
                    System.out.println(func.getID());

                }
            }

            oout.flush();
            oout.writeObject((Serializable) usuarios);// Responde para o usuário que conectou, enviando a lista de Funcionários
            oout.flush();

            clientes.add(oout);//Adiciona a conexão atual à coleção

            if (meuNome == null) {return;}

            sendToAll(oout);//Envia a coleção atualizada para todos os clientes já conectados
            
            String linha = entrada.readLine();

            while (linha != null && !(linha.trim().equals(""))) { //Fica no Loop até que o cliente envie uma String vazia

                linha = entrada.readLine();
            }


            for (Iterator I = usuarios.iterator(); I.hasNext();){// Aqui Atuaiza o usuário para o status "Desconectado"
                func = ((Funcionario) I.next());

                if ((func.getUserName().substring(16)).equals(meuNome)){
                    func.setID(null);
                    func.setStatus("Desconectado");

                    System.out.println((func.getUserName().substring(16))+" --> Funcionário desconectado");   
                }
            }


            sendToAll(oout);//Envia a lista atualizada para todos os Clientes

            clientes.remove(oout);
            conexao.close();

        }catch (IOException e) {
            // Caso ocorra alguma excessão de E/S, mostre qual foi.
            System.out.println("IOException: " + e);
        }
    }

    // enviar a lista para todos
    public void sendToAll(ObjectOutputStream saida) throws IOException {
        Enumeration e = clientes.elements();
        while (e.hasMoreElements()) {
            //OutputStream out = conexao.getOutputStream();
            ObjectOutputStream mandaBala = (ObjectOutputStream) e.nextElement();
            mandaBala.flush();
            mandaBala.writeObject((Serializable) usuarios);
            mandaBala.flush();
            System.out.println("Atualizando "+mandaBala);
        }
    }


}

Agradeço a alguma alma caridosa que me ajude ! :wink: