# ObjectOutputStream legt Servlet lahm



## JasDA (10. Dez 2009)

Ich habe in meiner Webanwendung neben einigen JSP-Seiten auch eine Servlet-Applet-Kombination. Servlet und Applet tauschen Objekte serialisiert über ObjectInputStream und ObjectOutputStream aus. Das sieht in etwa so aus:

Einmal das Servlet:

```
public void doPost(HttpServletRequest request, HttpServletResponse response)
			throws ServletException, IOException
	{				
		try 
		{
			response.setContentType("application/x-java-serialized-object");

			Map<String, Object> transfer = new HashMap<String, Object>();

			InputStream in = request.getInputStream();
			ObjectInputStream inputFromApplet = new ObjectInputStream(in);
			Map returnMap = (Map) inputFromApplet.readObject();
			
			// hier kann ich Daten aus dem Applet verarbeiten
			
			// echo it to the applet
			OutputStream outstr = response.getOutputStream();
			ObjectOutputStream oos = new ObjectOutputStream(outstr);
			oos.writeObject(transfer);
			oos.flush();
			oos.close();
		} 
		catch (Exception e) 
		{
			e.printStackTrace();
		}
	}
```


Und hier das Applet:

```
private void callServlet(String operation, String custNb, String titleNb, Integer dlvyNo)
	{		
		try 
		{			
			Map<String,Object> returnMap = new HashMap<String,Object>();
			returnMap.put("operation", operation);


			// send data to the servlet
			URLConnection con = getServletConnection("/App/secure/TestServlet/");
			OutputStream outstream = con.getOutputStream();
			ObjectOutputStream oos = new ObjectOutputStream(outstream);
			oos.writeObject(returnMap);
			oos.flush();
			oos.close();				


			// receive result from servlet
			InputStream instr = con.getInputStream();
			ObjectInputStream inputFromServlet = new ObjectInputStream(instr);
			Map transfer = (Map) inputFromServlet.readObject();
			inputFromServlet.close();
		} 
		catch (Exception ex) 
		{
			ex.printStackTrace();			
		}
	}
```

Das ganze funktioniert auf den ersten Blick auch erstmal ganz gut. Die call-Servlet Methode wird in der init-Methode des Applets aufgerufen, so dass die jTable im Applet Daten aus dem Servlet anzeigen kann. Ein Problem gibt es aber nun wenn ich die Seite verlasse und die Applet-Seite erneut aufrufe. Dann wird erneut die init-Methode aufgerufen und an folgender Stelle hängt sich das Servlet auf:

oos.writeObject(transfer);

Weiß nicht so recht warum das Servlet hier abstürzt (ohne Fehlermeldung). Die Stream-Obejekte werde nach der Verwendung geschlossen und sollten so "sauber" sein. Hab ich hier irgendwo etwas vergessen?


----------



## JasDA (11. Dez 2009)

Nachdem ich jetzt ein wenig rumprobiert und rumgelesen habe, habe ich zumindest die Ursache für den Fehler entdeckt. Der Fehler tritt immer genau dann auf, wenn das zu übertragende Objekt (hier die transfer-Map) sehr groß ist. Scheinbar hat der ObjectOutputStream generell ein Problem mit sehr großen Objekten wie immer wieder im Netz zu finden ist. Leider habe ich noch keine entsprechende Lösung gefunden dieses Problem zu umgehen


----------



## SlaterB (11. Dez 2009)

ist das Objekt denn auch kompliziert, von verschiedenster Beschaffenheit?
ansonsten könntest du auf ObjectStream verzichten und eine Darstellung als String, z.B. im XML-Format wählen,

dafür gibts sicher Tools, die vielleicht mit Beans mit getter/ setter klarkommen, ansonsten alles per Hand schreiben 
das wäre auf jeden Fall selbstkontrollierter Code, mit vielen aber ebenso kontrollierten Daten 
und die Übertragung einfacher Bytes/ Strings sollte keine Probleme bereiten


----------



## JasDA (11. Dez 2009)

Das Objekt ist leider kompliziert. In der HashMap werden gleich 4 andere Objekte eingebunden, die alle von einem anderen Typ sind und teilweise bis zu 30 Attribute beinhalten


----------



## SlaterB (11. Dez 2009)

zur Ergänzung noch Mittelweg:
jedes Objekt einzeln per einzelnen ObjectOutputStream + ByteArrayOutputStream in ein byte[] umwandeln, diese dann zusammen mit einem kleinen Map-Objekt mit den Informationen übertragen, was wohin gehört,
relativ unsauber und es könnte das Problem bleiben, dass eines der Teil-Objekte für sich immer noch zu groß ist

reden wir überhaupt von zig MB oder wieviel? 30 Attribute sollten doch nichts bedeuten, 
100.000 derartiger Objekte in einer Liste vielleicht..

> Scheinbar hat der ObjectOutputStream generell ein Problem mit sehr großen Objekten wie immer wieder im Netz zu finden ist.

Link?


----------



## JasDA (11. Dez 2009)

Es sind ca. 50.000 solcher Objekte in einer Liste ;-) Es wird damit eine komplette Tabelle im Applet gefüllt.

Und hier noch ein paar Links:
New To Java Technology Archive - writing large objects using ObjectOutputStream.writeObject()
writeObject too slow for big object, any idea?
...

writeObjet und large sind die passenden Suchbegriffe bei Google.


----------



## SlaterB (11. Dez 2009)

nun ja, 


SlaterB hat gesagt.:


> und es könnte das Problem bleiben, dass eines der Teil-Objekte für sich immer noch zu groß ist


dürfte dann wegfallen, 
speziell diese 50.000 Objekte einzeln in byte[] umzuwandeln dürfte keine Probleme machen,
wäre 'nur' die Übertragung und das Verständnis beim Java-Client zu organisieren

gehe ich richtig in der Annahme, dass in der Map mehrere Daten sind, davon ein paar ganz kleine
und noch die eine oder ein paar größere Listen?

dann wäre mein Vorschlag, diese Listen aus der ansonst gut kleinen Map rauszunehmen,
dafür stattdessen ein Verwaltungsobjekt mit einer Internet-Adresse zum separaten Nachladen der byte[]-Daten 
+ noch Beschreibung zu deren Interpretatation, etwa '43700x alle xy Bytes zusammen als ein Objekt einlesen'

nach der Aufteilung funktionieren ja auch mehr oder weniger Web-Seiten, 
Bilder sind nicht im HTML enthalten, nur die Links um sie zusätzlich nachzuladen


----------



## JasDA (14. Dez 2009)

Ich hab über's Wochenende nochmal einige Richtungen ausprobiert. Also in der Map sind ein paar Attribute und halt genau diese große Liste. Nun habe ich versucht, die Objekte in der Liste auseinanderzunehmen und im Applet wieder zusammenzusetzen. Ich habe also jedes einzelne Attribut manuell an den OutputStream angehängt und auch wieder ausgelesen.

In vielen Fällen reicht wirklich ein oos.writeInt etc. Da viele Attribute aber auch null sein können muss ich trotzdem dann das oos.writeObject verwenden. Nun hängt sich das Applet zwar nicht mehr auf aber wenn es öfters aufgerufen wird, erhalten ich den Fehler:



> Caused by: java.io.IOException: Eine bestehende Verbindung wurde softwaregesteuert
> durch den Hostcomputer abgebrochen
> at sun.nio.ch.SocketDispatcher.write0(Native Method)
> at sun.nio.ch.SocketDispatcher.write(SocketDispatcher.java:33)
> ...



Etwas merkwürdig finde ich nach wie vor, dass das Applet beim ersten Aufruf mit allen Daten problemlos angezeigt wird. Auch in der ursprünglichen Version die ich hatte. 

Das mit dem Verwaltungsobjekt habe ich zwar vom Prinzip her verstanden, allerdings fehlt mir da gerade das technische Verständnis. Könntest du den Ansatz vielleicht ein wenig genauer erklären? Denn mit den Streams stoße ich bei der Datenmenge vermutlich immer wieder an die Grenzen.


----------

