Serializacja - niezmienność obiektu

0

Witam.
Problem polega na tym, że podczas serializacji i wysyłania obiektu przez gniazda jego składowe(pola) zostają niezmienne pomimo ich zmiany. Przed wysłaniem obiektu sprawdzam jego zawartość i jasno wyświetla mi, że jest zmienione lecz po odczytaniu wyświetlana jest wartość z pierwszej serializacji(i taka zostaje do końca).

metody:

public void writeSerializedObject(Gamer gamer) {
		try {
			oos.writeObject(gamer);
			oos.flush();
			System.err.println("Wysłano obiekt");
		} catch (IOException e) {
			System.err.println("Błąd wysyłania obiektu");
		}
	}
	
public void readSerializedObject(Gamer gamer){
		try {
			gamer = (Gamer)ois.readObject();
			System.err.println("po odebraniu " +gamer.toString());
		} catch (IOException e) {
			
		} catch (ClassNotFoundException e) {
			
		}
}

w konstruktorze tworzę:

public Server(Socket s) throws IOException {
		socket = s;
		in = new BufferedReader(new InputStreamReader(socket.getInputStream()));
		System.err.println("-->Stworzono BufferedReader dla wątku");
		out = new PrintWriter(new BufferedWriter(new OutputStreamWriter(
				socket.getOutputStream())), true);
		System.err.println("-->Stworzono PrintWriter dla wątku");

		oos = new ObjectOutputStream(socket.getOutputStream());
		System.err.println("-->Stworzono ObjectOutputStream dla wątku");
		ois = new ObjectInputStream(socket.getInputStream());
		System.err.println("-->Stworzono ObjectInputStream dla wątku");

		start();
		System.err.println("-->Stworzono wątek dla klienta");
	}

potem w wątku odbieram dane od klienta:

@Override
	public void run() {
		Gamer gamer = null;
		while (true) {
			readSerializedObject(gamer);
		}
	}

klasa Gamer:

package siec;

import java.io.Serializable;

public class Gamer implements Serializable {
	private static final long serialVersionUID = 1L;
	public int x;
	public int y;
	public int power;
	public int angle;
	public int bomb_x;
	public int bomb_y;
	
	public Gamer() {
		//this.x = 1;
		//this.y = 2;
		//////itp
	}
	
	public void setX(int x) {
		this.x = x;
	}
	
	public void setY(int y) {
		this.y = y;
	}
	
	public void setPower(int power) {
		this.power = power;
	}
	
	public void setAngle(int angle) {
		this.angle = angle;
	}
	
	public int getX() {
		return x;
	}
	
	public int getY() {
		return y;
	}
	
	public int getPower() {
		return power;
	}
	
	public int getAngle() {
		return angle;
	}
	
	
	public String toString() {
		return "x=" + x + " y=" + y + " power=" + power + " angle=" + angle;
	}
}

Wydaje mi się, że wszystko jest ok.. Jakieś sugestie? Z góry dziękuje za pomoc.

0

Jaka jest rola parametru gamer w tej funkcji?

public void readSerializedObject(Gamer gamer){
                try {
                        gamer = (Gamer)ois.readObject();
                        System.err.println("po odebraniu " +gamer.toString());
                } catch (IOException e) {
 
                } catch (ClassNotFoundException e) {
 
                }
}

Podejrzewam, że masz w klasie pole gamer, a w powyższej funkcji zapamiętujesz odczytany obiekt do zmiennej lokalnej.

0
readSerializedObject(gamer);
//
gamer = (Gamer)ois.readObject();

No ale przecież w ten sposób wcale nie zmieniasz tego co chciałeś. W javie wszystko lata przez referencje więc przypisanie

gamer = (Gamer)ois.readObject();

nie powoduje wpisania nowych wartości do obiektu gamer, tylko podmienienie referencji. Zrób to jak normalny człowiek i zwyczajnie zwróć wartość z tej funkcji...

0

parametr w tej funkcji służy jako "in", czyli do tej zmiennej zapisuje sobie to co odczytam za pomocą readObject().
W swojej klasie głównej tworze pole Gamer gamer = new Gamer() i tam sobie operuje już na niej.

@Edit
Shalom nie do końca rozumiem o co chodzi. Na razie to i tak jest prototyp metody i ma najprostszą funkcjonalność.
zrobić coś takiego?

return (Gamer)ois.readObject();
1

Ale czytając w ten sposób nigdy nie zmieniasz zawartości pola gamer.
Wg mnie wystarczy zmiana nagłówka

public void readSerializedObject()
0

wedle Waszego rozumowania napisałem coś takiego:

public Gamer readSerializedObject(){
		Gamer gamer = null;
		try {
            gamer = (Gamer)ois.readObject();
    } catch (IOException e) {

    } catch (ClassNotFoundException e) {

    }
    return gamer;
}

@Override
public void run() {
		Gamer gamer = null;
		while (true) {
			gamer = readSerializedObject();
			System.out.println(gamer.toString());
		}
}

Dalej moge serializować i wysłać obiekt tylko jeden raz i wtedy on się zmieni, jeśli zrobię to ponownie składowe obiektu zostają takie same...

1

Teraz jest ok. Ale zapewne nic się nie dzieje bo leci ci wyjątek, który ładnie po cichu łapiesz i nawet o nim nie wiesz...

0

po obsłużeniu wyjątków niestety żaden z nich nie dał o sobie znać. Niby działa poprawnie..

@Edit
problem leżał w klasie ObjectOutputStream, ma do siebie takie coś, że czasami wysyła takie same zapamiętane dane. Należy po wysłaniu wywołać metodę reset().
Dziękuje Wam za pomoc. Temat do zamknięcia.

Poprawiona metoda:

public void writeSerializedObject(Gamer gamer) {
		try {
			oos.writeObject(gamer);
			oos.flush();
			oos.reset();
			System.err.println("Wysłano obiekt");
		} catch (IOException e) {
			System.err.println("Błąd wysyłania obiektu");
		}
	}
0

Nie, jest to normalne zachowanie, bo w odróżnieniu od innych input streamów metoda flush w ObjectOutputStream nie powoduje opróżnienia bufora i wpisanie do strumienia tego co w buforze siedziało, a jedynie przepisuje z bufora(kopia) do opakowanego strumienia wyjściowego. To co Ty chciałeś osiągnąć, (czyli takie zachowanie flush jak w np buforowanych strumieniach) tutaj można było po przez metode ObjectOutputStream#drain();
Polecam dokumentacje na przyszłość.

1 użytkowników online, w tym zalogowanych: 0, gości: 1