Serializacja - niezmienność obiektu

Serializacja - niezmienność obiektu
antoniaklja
  • Rejestracja:około 14 lat
  • Ostatnio:około 9 lat
  • Postów:88
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:

Kopiuj
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ę:

Kopiuj
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:

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

klasa Gamer:

Kopiuj
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.

bogdans
Moderator
  • Rejestracja:prawie 17 lat
  • Ostatnio:prawie 5 lat
0

Jaka jest rola parametru gamer w tej funkcji?

Kopiuj
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.


To smutne, że głupcy są tak pewni siebie, a ludzie mądrzy - tak pełni wątpliwości. Bertrand Russell
edytowany 1x, ostatnio: bogdans
Shalom
  • Rejestracja:około 21 lat
  • Ostatnio:około 3 lata
  • Lokalizacja:Space: the final frontier
  • Postów:26433
0
Kopiuj
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

Kopiuj
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...


"Nie brookliński most, ale przemienić w jasny, nowy dzień najsmutniejszą noc - to jest dopiero coś!"
antoniaklja
  • Rejestracja:około 14 lat
  • Ostatnio:około 9 lat
  • Postów:88
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?

Kopiuj
return (Gamer)ois.readObject();
edytowany 2x, ostatnio: antoniaklja
bogdans
Moderator
  • Rejestracja:prawie 17 lat
  • Ostatnio:prawie 5 lat
1

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

Kopiuj
public void readSerializedObject()

To smutne, że głupcy są tak pewni siebie, a ludzie mądrzy - tak pełni wątpliwości. Bertrand Russell
edytowany 1x, ostatnio: bogdans
antoniaklja
  • Rejestracja:około 14 lat
  • Ostatnio:około 9 lat
  • Postów:88
0

wedle Waszego rozumowania napisałem coś takiego:

Kopiuj
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...

edytowany 4x, ostatnio: antoniaklja
Shalom
  • Rejestracja:około 21 lat
  • Ostatnio:około 3 lata
  • Lokalizacja:Space: the final frontier
  • Postów:26433
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...


"Nie brookliński most, ale przemienić w jasny, nowy dzień najsmutniejszą noc - to jest dopiero coś!"
antoniaklja
  • Rejestracja:około 14 lat
  • Ostatnio:około 9 lat
  • Postów:88
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:

Kopiuj
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");
		}
	}
edytowany 1x, ostatnio: antoniaklja
Antoniossss
  • Rejestracja:prawie 16 lat
  • Ostatnio:ponad 10 lat
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ść.


www.toptraker.pl
TopTraker! - I wiesz co jest grane!
Mój własny projekt w Javie - najnowsza wersja już jest!

Zarejestruj się i dołącz do największej społeczności programistów w Polsce.

Otrzymaj wsparcie, dziel się wiedzą i rozwijaj swoje umiejętności z najlepszymi.