Java serializing

Moderators: jkien, Xilvo

Reageer
Gebruikersavatar
Berichten: 2.097

Java serializing

Ik ben momenteel bezig met een kaartspel te maken dat via een LAN-netwerk gespeeld kan worden.

Hierbij worden telkens geserialiseerde objecten verstuurd.

Maar ik heb 1 probleempje bij de volgende situatie:

class A implements Serializable

{

B b;

...

}

class B implements Serializable

{

Vector<C> c;

...

}

(de klasse C implementeert ook Serializable)

Het probleem is dat wanneer ik een object van klassa A verstuur, de vector A.b.c leeg aankomt bij de client, ook al was hij dat niet bij de server.

Er is geen enkele error bij het Serializeren of deserializeren.

Verder lijkt het versturen van klasses die rechtsreeks een vector als variabele hebben (dus niet via een andere variabele die op zijn beurt een vector heeft) wel te lukken.

Is er iets dat ik over het hoofd zie of vergeet?
"Why must you speak when you have nothing to say?" -Hornblower

Conserve energy: Commute with a Hamiltonian

Gebruikersavatar
Berichten: 829

Re: Java serializing

Ik weet niet meteen wat je verkeerd doet, maar je zou eventueel een methode in je B klasse kunnen voorzien alvorens je serialized die gewoon de Vector<C> omzet naar een C[] (array dus). Dat kan met de methode Vector.toArray() Mss werkt dat wel, ik weet het niet zeker, ik heb het ook niet geprobeerd, ik werk vooral met C# die heel anders op dat soort vlakken werkt.

P.S. Wat voor library gebruik je voor je LAN, als die niet aan Java zelf verbonden is, ben ik wel geïntresseerd om het ook voor doeleinden in C# te gebruiken.
"Als je niet leeft zoals je denkt, zul je snel gaan denken zoals je leeft."

--Vladimir Lenin-- (Владимир Ильич Ульянов)

Gebruikersavatar
Berichten: 2.097

Re: Java serializing

Nu ik wat verder heb gezocht, denk ik dat er een andere oorzaak is voor het probleem dat niets met de serializing te maken heeft.

Ik heb namelijk opgemerkt dat de vector geen elementen verliest, maar dat er een vroegere versie van de vector wordt opgestuurd, toen hij nog geen elementen had.

Situatieschets:

class Global

{

static A a;

}

class A

{

B b

}

class B

{

Vector<C> c;

}

en ergens anders gebeurt het volgende:

Executable e=new Executable(){

public void execute()

{

Global.a.b.c.add(...) // nieuw element in vector

Send();

});

e.execute();

waarbij Send(wél static) het object a verstuurd naar de client: writeObject(A.a)

Mijn gedacht was nu dat misschien wanneer het object e aangemaakt wordt, dat de methode writeObject(A.a) de A.a van dat moment neemt, namelijk het moment van de aanmaak van e. ipv de A.a die bestaat tijdens de uitvoering van de methode execute().

Als dit het geval is, hoe omzeil ik dit?
"Why must you speak when you have nothing to say?" -Hornblower

Conserve energy: Commute with a Hamiltonian

Gebruikersavatar
Berichten: 2.097

Re: Java serializing

P.S. Wat voor library gebruik je voor je LAN, als die niet aan Java zelf verbonden is, ben ik wel geïntresseerd om het ook voor doeleinden in C# te gebruiken.
De verbinding gebeurt met een Socket en ServerSocket

En schrijven en lezen gewoon met In en OutputStreams.

Dus alles is wel verbonden aan Java.
"Why must you speak when you have nothing to say?" -Hornblower

Conserve energy: Commute with a Hamiltonian

Gebruikersavatar
Berichten: 2.097

Re: Java serializing

Na wat verder testen is mijn tweede gedacht ook niet waar.

Er lijkt nog wat meer mis te lopen.

Ik heb een paar variabelen op het scherm laten printen voor het versznden en na het verzenden.

Ook de naam van de doorgestuurde kaart verandert van zijn normale String naar '[]'

en andere variabelen die op null springen.

Ik heb nu eens geprobeerd met het omzetten naar een array, maar die wordt zelfs helemaal null.

Ik ga er morgen nog eens naar kijken.
"Why must you speak when you have nothing to say?" -Hornblower

Conserve energy: Commute with a Hamiltonian

Gebruikersavatar
Berichten: 829

Re: Java serializing

Ik denk dat het in dat geval niet noodzakelijk aan de serialisatie ligt, heb je eens geprobeerd te serializen en terug gewoon in een eenvoudige ByteArrayInputStream, want mss ligt het gewoon aan het zenden, is de verbinding alvorens ermee te werken goed in Java geconfigureerd?
"Als je niet leeft zoals je denkt, zul je snel gaan denken zoals je leeft."

--Vladimir Lenin-- (Владимир Ильич Ульянов)

Berichten: 202

Re: Java serializing

Kun je misschien meer van je java code posten? We zitten zo maar een beetje te gokken hier...

Waarom gebruik je Serializable?

Gebruikersavatar
Berichten: 2.097

Re: Java serializing

meijuh schreef:Kun je misschien meer van je java code posten? We zitten zo maar een beetje te gokken hier...

Waarom gebruik je Serializable?
Is er nog een andere manier om dingen te verzenden buiten Serializing?

Ik zal misschien een uitgebreidere omschrijving geven.

Er zijn twee spelers, de server en client, die beide hetzelfde programma openen.

Deze spelers zitten in het programma als volgt:

Verborgen inhoud
class Players

{

public static Player thisPlayer,otherPlayer;

}


Elke speler heeft 1 actieve kaart op het veld en tot 5 andere niet-actieve kaarten (Bench):

Verborgen inhoud
class Player implements Serializable

{

public ActiveCard activeCard;

public Bench bench;

}


ActiveCard:

Verborgen inhoud
class ActiveCard implements Serializable

{

Card card;

}


Bench:

Verborgen inhoud
class Bench implements Serializable

{

Card[] card;

}


en Card zelf:

Verborgen inhoud
class Card implements Serializable

{

Source source

Vector<Source> attachedCards;

}


waarbij Source de kaart beschrijft, dus welke afbeelding, de naam en andere gegevens.

Nu kan een speler een kaart toevoegen aan de attachedCards van de actieve kaart.

Dit gebeurt als volgt:

De speler klikt op de knop dat hij een kaart wil toevoegen. Op dit moment wordt een opdrach aangemaakt die uitgevoerd wordt wanneer de speler op de actieve kaart klikt:

Verborgen inhoud
Executable e=new Executable(){

public void execute()

{

Players.thisPlayer.activeCard.attachedCards.add(getSelectedCard());

Update.updateActive(true);

}

}

onLeftClick=e;


wanneer de speler dan klikt gebeurt: onLeftClick.execute()

De geselecteerde kaart wordt dus toegevoegd, waarna een update hierrvan wordt verstuurd naar de andere speler.

Update:

Verborgen inhoud
public class Update implements Serializable

{

Object o;

boolean bool;

public Update(Object o)

{

this.o=o;

}

public static updateActive()

{

Send.send(new Update(Players.thisPlayer.activeCard));

}


De methode send() stuurt het object door via de outputsream van de server of client.

Wanneer een object binnenkomt gebeurt het volgende:

Verborgen inhoud
public static void whatToDo(Object ob)

{

if (ob instance of Update)

{

if (ob.o instance of ActiveCard)

{

Players.otherPlayer.activecard=(ActiveCard)ob.o;

}

}

}


Waar zit nu het probleem:

De andere speler krijgt probleemloos het object van Update aan.

Er zit de juiste kaart in, maar de vector attachedCards is nog altijd leeg. De kaart werd dus niet toegevoegd.

Een gelijkaardig probleem treedt op bij het verwisselen van kaarten:

Een speler kan zijn actieve kaart wisselen met een van zijn niet-actieve kaarten (bench):

Verborgen inhoud
public void switch(int benchSlot)

{

ActiveCad temp=Players.thisPlayer.activeCard.card;

Players.thisPlayer.activeCard.card=Players.thisPlayer.bench.card[benchSlot];

Players.thisPlayer.bench.card[benchSlot].card=temp;

Update.updateActive();

Update.updateBench(benchSlot);

}


updateBench is analoog aan updateActive.

De andere speler krijgt nu dus twee Updates aan, 1 met de nieuwe actieve kaart, en 1 met de nieuwe niet-actieve kaart.

Maarde actieve kaart die hij aankrijgt is nog steeds de oude, niet de verwisselde, idem voor de bench-kaart.

Maw, er is dus niets verandert voor de andere speler.

ik dacht eens te kijken wat er gebeurt door af te printen wat er verzonden wordt en wat ontvangen wordt.

Dus in de methode updateActive:

println(Players.thisPlayer.activeCard.card.toString());

en in de methode whatToDo(ActiveCard a):

println(a.card.toString());

Stel dat bij het verwisselen de originele actieve kaart 'Original' heet, en de nieuwe 'New'.

Dan zien we bij de verzender het volgende: 'Original'

Maar de ontvanger print 'New'.

Hetzelfde bij het toevoegen van een kaart: als ik bij de verzender de groote van de vector attachedCards print, krijg ik 1, terwijl de ontvanger 0 print.

Ik heb al een oplossing gevonden voor het wisselen van twee kaarten, al weet ik wel niet waarom die werkt:

in plaats van de originele Update.updateActive te gebruiken, heb ik deze vervangen door:

Verborgen inhoud
public void updateActive()

{

Send.send(new Update(Players.thisPlayer.activeCard.getCopy()));

}


Door getCopy() te schrijven, krijgt de andere speler wél de vernieuwde kaart aan.

getCopy:

Verborgen inhoud
public class ActiveCard imlplements Serializable

{

public ActiveCard getCopy()

{

ActiveCard copy=new ActiveCard();

copy.card=this.card;

... // en de andere variabelen worden ook zo gekopieerd.

}

}


Dit werkt dus wel voor het wisselen, maar nog altijd niet voor het toevoegen van een kaart.

Ik heb heel deze ochtend liggen testen en mij lijkt het of de methode updateActive() toch een vroegere variant

van Players.thisPlayer.activeCard doorstuurt.

Als het misschien meer duidelijkheid zou brengen, wil ik gerust de huidige code wel op internet zetten, mocht iemand die willen doorworstelen (ik ben nogal een slordige programmeur).
"Why must you speak when you have nothing to say?" -Hornblower

Conserve energy: Commute with a Hamiltonian

Gebruikersavatar
Berichten: 4.810

Re: Java serializing

Ik heb niet heel je code bekeken, maar ik vermoed dat je ergens objecten hebt zitten die serializable niet implementeren. Een andere mogelijkheid is dat er ergens static variabelen aanwezig zijn die het boeltje om zeep helpen.

Gebruikersavatar
Berichten: 2.097

Re: Java serializing

Ik heb niet heel je code bekeken, maar ik vermoed dat je ergens objecten hebt zitten die serializable niet implementeren. Een andere mogelijkheid is dat er ergens static variabelen aanwezig zijn die het boeltje om zeep helpen.
Ik heb alles nagekeken, en alles implementeert Serializable, dit zou trouwens een Exception geven denk ik.

Wat bedoel je met die static variabelen?

Het object dat ik opstuur is een static variabele van een bepaalde klasse; de ontvanger kopieert het ontvangen object in een andere static variabele van een bepaalde klasse.
"Why must you speak when you have nothing to say?" -Hornblower

Conserve energy: Commute with a Hamiltonian

Gebruikersavatar
Berichten: 2.097

Re: Java serializing

Het probleem is opgelost, vreemd genoeg snap ik wel niet waarom dat zo is ;)

Ik vermoed dat al die statics er toch voor iets tussenzitten.

Dus even recapituleren:

een non-static methode verandert een static variabele.

Dezelfde non-static methode roept dan een static methode op die in een nieuw object de static variabele steekt.

De laatste static methode roept dan een andere static methode op die het nieuw aangemaakte object doorstuurt.

Wat ik nu heb aangepast is dat ik niet rechtstreeks de static variabele doorstuur.

Dus niet: Send.send(new Update(Players.thisPlayer.activeCard));

Maar ik heb in ActiveCard en in Card een non-static methode aangemaakt getCopy() die een nieuw, identiek object teruggeeft, zoals clone() eigenlijk.

En als ik dat verstuur, dan stuur ik wel de aangepast versie door.

Maar waarom je anders de oorspronkelijke versie doorstuurt, dat weet ik niet.
"Why must you speak when you have nothing to say?" -Hornblower

Conserve energy: Commute with a Hamiltonian

Gebruikersavatar
Berichten: 7.224

Re: Java serializing

En wel hierom:
Trap 1: Hidden Caching

We found our first trap in a client/server setting. We wanted to resend objects when their values changed. But we saw that although the object had been sent again, it still had its original value. Much to our surprise we discovered that the default behavior for Java serialization was to serialize any unique object (as determined by a comparison of the memory address of the object to be serialized with that of all objects previously serialized) just once. The serialized form is cached and then sent again when requested. This design decision helps speed up serialization for applications that are just passing objects as messages, not for their internal values. However, it's not obvious to beginning users that this caching is happening. Each time you try to serialize the object, you'll get that first cached instance again. If you want the serialized object to reflect changes in the "source" object, call the reset() method.
http://java.sys-con.com/node/36149
If I have seen further it is by standing on the shoulders of giants.-- Isaac Newton

Gebruikersavatar
Berichten: 2.097

Re: Java serializing

Trap 1: Hidden Caching
Dat verklaart veel...

Bedankt, je bespaart weer een slapeloze nacht, te piekeren waar de fout zou kunnen zitten!
"Why must you speak when you have nothing to say?" -Hornblower

Conserve energy: Commute with a Hamiltonian

Reageer