# Serialisierung und Deserialisierung einer HashMap



## zco (23. Okt 2008)

Hallo zusammen,

ich versuche nun seit ein paar Stunden vergeblich ein HashMap zu serialisieren/deserialisieren. Mir ist die Vorgehensweise irgendwie nicht ganz klar. 

Ic würde das gerne mit dem ObjectOutputStream bzw. ObjectInputStream machen. Dazu gibt es auch einige Beispiele, unter anderem im Java-Insel-Buch oder im Artikel "A Taste of Java's I/O Package: Streams, Files, and So Much More" auf InformIT, welche allerdings immer eine Datei als Zwischenlagerungsmedium verwenden. Ich möchte gerne einen String verwenden. Das heißt ich serialisiere die HashMap in einen String und deserialisiere die Map aus diesem String danach wieder. Aber irgendwie weiß ich nicht so richtig welche Stream-Klassen ich da nehmen muss und wie ich da ran gehe.

Ich hoffe ihr könnt mir helfen.

Viele Grüße,
zco


----------



## maki (23. Okt 2008)

>> Ich möchte gerne einen String verwenden. Das heißt ich serialisiere die HashMap in einen String und deserialisiere die Map aus diesem String danach wieder.

Geht nicht, wäre auch Quatsch.


----------



## enemy (23. Okt 2008)

such mal nach object to byte[].


----------



## FArt (23. Okt 2008)

maki hat gesagt.:
			
		

> >> Ich möchte gerne einen String verwenden. Das heißt ich serialisiere die HashMap in einen String und deserialisiere die Map aus diesem String danach wieder.
> 
> Geht nicht, wäre auch Quatsch.



Geht schon, bleibt aber Quatsch ;-)


----------



## zco (23. Okt 2008)

danke erstmal für die Antworten.

@maki & FArt: Warum wäre das Quatsch?  ???:L 

@enemy: schau ich mir grad an, mal sehen ob ich es hinbekomme


----------



## maki (23. Okt 2008)

>> Geht schon, bleibt aber Quatsch 

Quatsch sollte man verbieten 

>> Warum wäre das Quatsch?

Wozu sollte das denn gut sein????


----------



## zco (23. Okt 2008)

@Wozu sollte das denn gut sein?: 

Ich glaube ich versuche mal meinen Fall genauer zu beschreiben.  :wink: 

Ich verwende Project Zero (www.projectzero.org) um einen leichtgewichtigen Web Service zu bekommen. Dort gibt es die Möglichkeit mit Hilfe der Methode GlobalContext.zput(pfad, objekt) ein Objekt in einer Art globaler Speicher zu verwalten. Wenn mein Code nach der Ausführung des Services nun wieder bei mir verarbeitet wird möchte ich gerne das zurückgegebene Ergebnis haben. Mit zput kann ich nur bestimmte Objekte übergeben, wie zum Beispiel eine HashMap, einen String, ... . Die HashMap wir in der Form serialisiert (keine Ahnung wie und mit was) so das folgender String heraus kommt (Beispiel) : [{"name1":"value1"}{"name2":"value2"}]. In meiner naiven Vorstellung dachte ich ich könnte das ganze einfach wieder deserialisieren, sodass eine HashMap heraus kommt.

Zum Vorschlag von enemy mit byte[] daran zu gehen nützt mir leider auch nicht viel, da ich irgendwie den Byte Array übergeben muss. Das mache ich dann als String und damit kommt die Deserialisierung nicht mit klar (logischer Weise).

Ich kann die HashMap also beliebig serialisieren, übergeben tu ich aber einen String. Entsprechend macht es in diesem Fall schon Sinn (kein Quatsch :wink: ) die HashMap derart zu serialisieren und deserialisieren.

Gruß


----------



## enemy (23. Okt 2008)

object to byte[]
new String(byte[]) xD


----------



## FArt (23. Okt 2008)

enemy hat gesagt.:
			
		

> object to byte[]
> new String(byte[]) xD


Schon wieder Quatsch. Doppelquatsch. Damit handelst du dir Encodingprobleme ein.

Wenn es denn schon sein muss, dann Base64 enkodiert.

Ein wenig schöner: XMLEncoder/XMLDecoder... funktioniert mit allen Beans out of the box...


----------



## zco (23. Okt 2008)

OK, ich nutze jetzt einen ByteArrayOutputStream und einen ObjectOutputStream um eine HashMap<String, String> zu serialisieren. Dann nutze ich die Funktion toByteArray() um das Ergebnis des ByteArrayOutputStream in ein byte[] array zu bekommen, welchen ich dann mit new String(byte[]) zu einem String umwandle. Das sende ich zurück.

Auf der anderen Seite verwende ich einen BufferredReader um den String zu bekommen. Mit string.getBytes() bekomme ich wieder ein byte Array, was ich einem ByteArrayInputStream übergebe. Diesen übergebe ich dann einem ObjectInputStream wo ich versuche mit readObject() die HashMap wieder zu bekommen. Das schlägt jedoch mit der folgenden Exception fehl.

java.io.StreamCorruptedException: invalid stream header


----------



## FArt (23. Okt 2008)

zco hat gesagt.:
			
		

> OK, ich nutze jetzt einen ByteArrayOutputStream und einen ObjectOutputStream um eine HashMap<String, String> zu serialisieren. Dann nutze ich die Funktion toByteArray() um das Ergebnis des ByteArrayOutputStream in ein byte[] array zu bekommen, welchen ich dann mit new String(byte[]) zu einem String umwandle. Das sende ich zurück.
> 
> Auf der anderen Seite verwende ich einen BufferredReader um den String zu bekommen. Mit string.getBytes() bekomme ich wieder ein byte Array, was ich einem ByteArrayInputStream übergebe. Diesen übergebe ich dann einem ObjectInputStream wo ich versuche mit readObject() die HashMap wieder zu bekommen. Das schlägt jedoch mit der folgenden Exception fehl.
> 
> java.io.StreamCorruptedException: invalid stream header



Hast du eine JUnit Test für deine Konvertierung oder bist du mehr für den explorativen Ansatz und lässt andere für dich denken? Vergleiche mal das ursprüngliche Array mit dem Ergebnis und lies meinen letzten Post. Entwickel ein wenig Eigeninitiative.


----------



## tuxedo (23. Okt 2008)

Wo ist denn da das Problem?!


```
HashMap<String, String> beforeMap = new HashMap<String, String>();
	
	beforeMap.put("myKey1", "myValue1");
	beforeMap.put("myKey2", "myValue2");
	beforeMap.put("myKey3", "myValue3");
	
	ByteArrayOutputStream baos = new ByteArrayOutputStream();
	ObjectOutputStream oos = new ObjectOutputStream(baos);
	
	oos.writeObject(beforeMap);
	oos.flush();
	
	byte[] serializedMap = baos.toByteArray();
	
	String serializedMapAsString = new String(serializedMap);
	
	System.out.println(serializedMapAsString);
	
	byte[] serializedMapReceived = serializedMapAsString.getBytes();
	
	ByteArrayInputStream bais = new ByteArrayInputStream(serializedMapReceived);
	ObjectInputStream ois = new ObjectInputStream(bais);
	HashMap<String, String> afterMap = (HashMap<String, String>) ois.readObject();
	
	System.out.println(afterMap.get("myKey1"));
	System.out.println(afterMap.get("myKey2"));
	System.out.println(afterMap.get("myKey3"));
```

Alles worauf du achten musst, ist das String-Encoding. Solltest halt sicherstellen dass auf beiden Seiten das gleiche Encoding benutzt wird und es sich unterwegs nicht ändert oder "Sonderzeichen" eliminiert werden ...

- Alex


----------



## enemy (23. Okt 2008)

@FArt, schon wieder? habe ich noch irgendwo was 'unsinniges' geschrieben?

ich sehe aber schon, da ist jemand sehr von sich überzeugt und wirft gern mit großen worten rum...


----------



## FArt (23. Okt 2008)

enemy hat gesagt.:
			
		

> @FArt, schon wieder? habe ich noch irgendwo was 'unsinniges' geschrieben?


Kann schon sein, bei den Gästen kann man das ja nicht so einfach nachvollziehen... *G*

Nichts desto trotz: dein Ansatz ist suboptimal, weil inkonsistent, besonders weil du nicht in der Hand hast wo der String dann alles verarbeitet wird => Quatsch. Der Quatsch wird nicht geringer, nur weil der Fehler nicht sofort offenbar wird.


----------



## zco (23. Okt 2008)

Hi Alex,

ich mache es praktisch genauso wie du (sogar schon bevor du mir deinen Code geschickt hast), abgesehen von den Variablennamen :wink: . Trotzdem bekomme ich die Exception. Wenn ich mir den die Bytes ausgeben lasse habe ich folgendes:

"\u00ac\u00ed\0\u0005sr\0\u0011java.util.HashMap\u0005\u0007\u00da\u00c1\u00c3\u0016`\u00d1\u0003\0\u0002F\0\nloadFactorI\0\tthresholdxp?@\0\0\0\0\0\fw\b\0\0\0\u0010\0\0\0\u0004t\0\u00014t\0\u0006fourtht\0\u00013t\0\u0005thirdt\0\u00012t\0\u0006secondt\0\u00011t\0\u0005firstx"

Da steht sogar HashMap drin, aber wie gesagt, wieder: java.io.StreamCorruptedException: invalid stream header

Ich habe das serialisierte Ergebnis mit dem String vor der Deserialisierung verglichen. Diese sind identisch. Also sollte "unterwegs" nichts verloren gegangen sein.

@FArt: Sorry das es vllt. so rüberkommt, das ich andere denken lasse. Dem ist aber nicht so, denn es nützt mir ja nichts wenn ich es selbst nicht begreife. Was die Eigeninitiative anbelangt weiß ich nicht was ich noch mehr machen sollte außer gestern Abend 4 Stunden und heute schon den ganzen Tag mich damit zu beschäftigen. Was deinen Vorschlag mit XMLEncoder/XMLDecoder anbelangt bin ich noch dabei das auszuprobieren. Bin nunmahl nicht der schnellste...


----------



## tuxedo (23. Okt 2008)

>> Ich habe das serialisierte Ergebnis mit dem String vor der Deserialisierung verglichen. Diese sind identisch.

Irgendetwas MUSS an dem String anders sein, sonst würde es ja klappen (mein Codesample ist immerhin lauffähig). Versuch das ganze doch erstmal lokal als Dummy zum laufen zu kriegen und erweitere das ganze dann Stück für Stück. Wenn du bytes in einen String wandelst und später wieder zurück, solltest du, wenn du verlgleichst, nicht auf String-Ebene vergleichen, sondern auf byte-Ebene Also VOR dem in String wandeln, und NACH dem von String in Byte wandeln...



@FArt:

Dein Einwand ist also, dass man es nicht in der Hand hat wer den String alles noch manipuliert, umformt etc?! Naja. Finde das ist Ansichtssache. Ein String ist ja auch nix weiter als eine (terminierte) Byte-Folge. 

Wenn ich das mit dem String weglasse, lasse ich das Wörtchen "String" und das mit dem "terminiert" weg. Es ist und bleibt doch aber eine Byte-Folge. Und die kann ich unterwegs genausogut manipulieren und umformen/konvertieren. 

Wenn auf beiden Seiten die gleiche "Sprache" gesprochen wird, sollte String oder Nicht-String keine Rolle spielen.

- Alex


----------



## FArt (23. Okt 2008)

tuxedo hat gesagt.:
			
		

> Wenn auf beiden Seiten die gleiche "Sprache" gesprochen wird, sollte String oder Nicht-String keine Rolle spielen.
> - Alex


Genau das ist ja das Problem. Sobald ich die Zeichenkette auf einem System verarbeite, welches ein anderes Encoding benutzt, ist u.U. alles hinüber. Da kann ich beim hin- und zurückwandeln das gleiche Encoding verwenden, zwischendurch kann der Text bei "unsachgemäßer" Verbeitung und Speicherung unwiederbringlich verhunzt werden. 
Hier wird wohl der Webservice und/oder der Zugriff darauf schuld sein.



> Ich verwende Project Zero (www.projectzero.org) um einen leichtgewichtigen Web Service zu bekommen. Dort gibt es die Möglichkeit mit Hilfe der Methode GlobalContext.zput(pfad, objekt) ein Objekt in einer Art globaler Speicher zu verwalten. Wenn mein Code nach der Ausführung des Services nun wieder bei mir verarbeitet wird möchte ich gerne das zurückgegebene Ergebnis haben. Mit zput kann ich nur bestimmte Objekte übergeben, wie zum Beispiel eine HashMap, einen String, ... . Die HashMap wir in der Form serialisiert (keine Ahnung wie und mit was) so das folgender String heraus kommt (Beispiel) : [{"name1":"value1"}{"name2":"value2"}]. In meiner naiven Vorstellung dachte ich ich könnte das ganze einfach wieder deserialisieren, sodass eine HashMap heraus kommt.



Wetten, dass wir hier um das Problem diskutieren, das mehrfach als Quatsch bezeichnet wurde? Liege ich falsch, gebe ich dir ein Bier aus ;-)
... auch zwei...


----------



## tuxedo (23. Okt 2008)

>> Genau das ist ja das Problem. Sobald ich die Zeichenkette auf einem System verarbeite, welches ein anderes Encoding benutzt, ist u.U. alles hinüber.

Klar. So ganz die piek feine Sache ist es nicht Daten als String zu handhaben. Aber es gibt ja für alles einen sinnvollen Verwendungszweck und ebenso einen nicht sinnvollen.

Wenn man es  nicht in der Hand hat, wer alles den String noch in die Hand bekommt und damit herumhantiert (so viel Hand ... :autsch: ), dann sollte man wohl von der String-Lösung abstand nehmen...


----------

