Springen naar inhoud

Java serializing


  • Log in om te kunnen reageren

#1

ZVdP

    ZVdP


  • >1k berichten
  • 2097 berichten
  • VIP

Geplaatst op 09 juli 2009 - 21:15

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

Dit forum kan gratis blijven vanwege banners als deze. Door te registeren zal de onderstaande banner overigens verdwijnen.

#2

Vladimir Lenin

    Vladimir Lenin


  • >250 berichten
  • 829 berichten
  • Ervaren gebruiker

Geplaatst op 09 juli 2009 - 21:49

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-- (Владимир Ильич Ульянов)

#3

ZVdP

    ZVdP


  • >1k berichten
  • 2097 berichten
  • VIP

Geplaatst op 09 juli 2009 - 21:53

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?

Veranderd door ZVdP, 09 juli 2009 - 21:55

"Why must you speak when you have nothing to say?" -Hornblower
Conserve energy: Commute with a Hamiltonian

#4

ZVdP

    ZVdP


  • >1k berichten
  • 2097 berichten
  • VIP

Geplaatst op 09 juli 2009 - 22:00

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

#5

ZVdP

    ZVdP


  • >1k berichten
  • 2097 berichten
  • VIP

Geplaatst op 09 juli 2009 - 22:48

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

#6

Vladimir Lenin

    Vladimir Lenin


  • >250 berichten
  • 829 berichten
  • Ervaren gebruiker

Geplaatst op 10 juli 2009 - 07:35

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-- (Владимир Ильич Ульянов)

#7

meijuh

    meijuh


  • >100 berichten
  • 202 berichten
  • Ervaren gebruiker

Geplaatst op 10 juli 2009 - 09:13

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

#8

ZVdP

    ZVdP


  • >1k berichten
  • 2097 berichten
  • VIP

Geplaatst op 10 juli 2009 - 13:24

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

#9

Cycloon

    Cycloon


  • >1k berichten
  • 4810 berichten
  • VIP

Geplaatst op 10 juli 2009 - 14:48

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.

#10

ZVdP

    ZVdP


  • >1k berichten
  • 2097 berichten
  • VIP

Geplaatst op 10 juli 2009 - 15:00

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

#11

ZVdP

    ZVdP


  • >1k berichten
  • 2097 berichten
  • VIP

Geplaatst op 10 juli 2009 - 16:20

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.

Veranderd door ZVdP, 10 juli 2009 - 16:22

"Why must you speak when you have nothing to say?" -Hornblower
Conserve energy: Commute with a Hamiltonian

#12

Bart

    Bart


  • >5k berichten
  • 7224 berichten
  • VIP

Geplaatst op 10 juli 2009 - 18:13

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

#13

ZVdP

    ZVdP


  • >1k berichten
  • 2097 berichten
  • VIP

Geplaatst op 10 juli 2009 - 18:24

Trap 1: Hidden Caching


Dat verklaart veel...

Bedankt, je bespaart weer een slapeloze nacht, te piekeren waar de fout zou kunnen zitten!

Veranderd door ZVdP, 10 juli 2009 - 18:25

"Why must you speak when you have nothing to say?" -Hornblower
Conserve energy: Commute with a Hamiltonian





0 gebruiker(s) lezen dit onderwerp

0 leden, 0 bezoekers, 0 anonieme gebruikers

Ook adverteren op onze website? Lees hier meer!

Gesponsorde vacatures

Vacatures