# NotSerializableException



## Tenori (3. Jan 2010)

Guten Tag,
als Übungsaufgabe soll ich eine Rohform einer Studentenverwaltung programmieren, wo man Studenten(Vorname, name, Matrikelnummer) eintragen kann, und diese dann in einer .txt-Datei gespeichert werden, und beim erneuten Aufruf einer StudentenVerwaltung wieder geladen werden.
Ich poste einfach ma den Code:

```
//Datei:StudentenVerwaltung.java

import java.io.*;
import java.util.*;

public class StudentenVerwaltung
{
	class StudentenAdresse implements Serializable
	{
		private int matrikelnummer;
		private String name;
		private String vorname;
		
		StudentenAdresse(int matrikelnummer,String name, String vorname)
		{
			this.matrikelnummer = matrikelnummer;
			this.name = name;
			this.vorname = vorname;
		}
		StudentenAdresse()
		{
			matrikelnummer = 0;
			name = "unknown";
			vorname = "unknown";
		}
		
		String getName()
		{
			return name;
		}
		
		String getVorname()
		{
			return vorname;
		}
		
		int getMatrikelnummer()
		{
			return matrikelnummer;
		}
		
		void print()
		{
			System.out.println("Initialisiere Ausgabe des Studenten...");
			System.out.println("Vorname: " + vorname);
			System.out.println("Name: " + name);
			System.out.println("Matrikelnummer: " + matrikelnummer);
			System.out.println("Ausgabe beendet.");
			System.out.println();
		}
	}
	
	private Map<Integer,StudentenAdresse> sammlung;
	private ObjectOutputStream objectOut;
	private ObjectInputStream objectIn;
	
	public StudentenVerwaltung()
	{
		try
		{
			sammlung = new HashMap<Integer,StudentenAdresse>();
			objectOut = new ObjectOutputStream(new FileOutputStream("Studenten.txt"));
			objectIn = new ObjectInputStream(new FileInputStream("Studenten.txt"));
			load();
		}
		catch(Exception e)
		{
			e.getMessage();
		}
	}
	
	public void add(int matrikelnummer, String vorname, String name)
	{
		StudentenAdresse s = new StudentenAdresse(matrikelnummer,name,vorname);
		sammlung.put(s.getMatrikelnummer(),s);
	}
	
	public void get(int matrikelnummer)
	{
		sammlung.get(matrikelnummer).print();
	}
	
	public void save() throws Exception
	{
		List<StudentenAdresse> list = new ArrayList<StudentenAdresse>(sammlung.values());
		for(StudentenAdresse e : list)
		{
			objectOut.writeObject(e);
		}
	}
	
	private void load() throws Exception
	{
		StudentenAdresse tmp = new StudentenAdresse();
		while((tmp=(StudentenAdresse)objectIn.readObject()) != null)
		{
			sammlung.put(tmp.getMatrikelnummer(),tmp);
		}
	}
	
	protected void finalize()
	{
		try
		{
			objectOut.close();
			objectIn.close();
		}
		catch(Exception e)
		{
			e.getMessage();
		}
	}
}
```


```
//Datei: Test.java

public class Test
{
	public static void main(String[] args)
	{
		try
		{
			StudentenVerwaltung s1 = new StudentenVerwaltung();
			s1.add(12345,"test1a","test1b");
			s1.add(123456,"test2a","test2b");
			s1.add(567891,"test3a","test3b");
		
			s1.get(12345);
			s1.get(123456);
			s1.get(567891);
		
			s1.save();
			StudentenVerwaltung s2 = new StudentenVerwaltung();
			System.out.println("Neues Objekt der Verwaltung");
			s2.get(12345);
			s2.get(123456);
			s2.get(567891);
		}
		
		catch(Exception e)
		{
			try
			{
				System.out.println("Ein unerwarteter Fehler ist aufgetreten!");
				PrintStream p1 = new PrintStream(new FileOutputStream("Error.txt"));
				System.setErr(p1);
				e.printStackTrace();
			}
			catch(Exception z)
			{
				System.out.println("Fehler beim Schreiben!");
			}
		}
	}
}
```

Hier der Error-Log:

```
//Datei: Error.txt

java.io.NotSerializableException: StudentenVerwaltung
	at java.io.ObjectOutputStream.writeObject0(Unknown Source)
	at java.io.ObjectOutputStream.defaultWriteFields(Unknown Source)
	at java.io.ObjectOutputStream.writeSerialData(Unknown Source)
	at java.io.ObjectOutputStream.writeOrdinaryObject(Unknown Source)
	at java.io.ObjectOutputStream.writeObject0(Unknown Source)
	at java.io.ObjectOutputStream.writeObject(Unknown Source)
	at StudentenVerwaltung.save(StudentenVerwaltung.java:86)
	at Test.main(Test.java:19)
```

Ich blicke irgendwie nichtmehr durch, die Klasse StudentenAdresse implementiert doch das Interface Serializable, darum versteh ich net wieso eine NotSerializableException geworfen wird..

Danke schonmal,

Grüße und frohes Neues so btw =)


----------



## freez (3. Jan 2010)

Eine Antwort auf deine konkrete Frage habe ich nicht. Mir ist nur was aufgefallen. Wie lautet denn die genaue Aufgabenbeschreibung bzgl. des Speicherns? Du schreibst in eine *.txt Datei. Von Natur aus sind solche Dateien lesbar für Menschen (also Texte). Eine Datei mit ObjectOutputStream geschrieben kann so nicht gelesen werden.

Wenn es so sein sollte, wie ich vermute, habe ich natürlich eine Idee, wie du es lesbar in eine TXT Datei bekommst.

Und gleich noch einen Tipp:
Falls dein Prof dieses Programm erweitert haben will, kann deine inner Class "StudentenAdresse" zu einem Problem werden. Erstell sie als separate Klasse in einer .java Datei. Ausser, du weist, dass du sie nie in einer anderen Klasse benötigst.


----------



## Tenori (3. Jan 2010)

In der .txt-Datei soll es nicht lesbar sein , wichtig ist nur, dass man sich im Endeffekt in der Konsole die Daten ausgeben lassen kann.

Grüße


----------



## eRaaaa (3. Jan 2010)

Probier mal StudentenAdresse *nicht* als Mitgliedsklasse von StudentenVerwaltung zu definieren:


```
//Datei:StudentenVerwaltung.java

import java.io.*;
import java.util.*;

public class StudentenVerwaltung
{

	private Map<Integer,StudentenAdresse> sammlung;
	private ObjectOutputStream objectOut;
	private ObjectInputStream objectIn;
	
	public StudentenVerwaltung()
	{
		try
		{
			sammlung = new HashMap<Integer,StudentenAdresse>();
			objectOut = new ObjectOutputStream(new FileOutputStream("Studenten.txt"));
			objectIn = new ObjectInputStream(new FileInputStream("Studenten.txt"));
			load();
		}
		catch(Exception e)
		{
			e.getMessage();
		}
	}
	
	public void add(int matrikelnummer, String vorname, String name)
	{
		StudentenAdresse s = new StudentenAdresse(matrikelnummer,name,vorname);
		sammlung.put(s.getMatrikelnummer(),s);
	}
	
	public void get(int matrikelnummer)
	{
		sammlung.get(matrikelnummer).print();
	}
	
	public void save() throws Exception
	{
		List<StudentenAdresse> list = new ArrayList<StudentenAdresse>(sammlung.values());
		for(StudentenAdresse e : list)
		{
			objectOut.writeObject(e);
		}
	}
	
	private void load() throws Exception
	{
		StudentenAdresse tmp = new StudentenAdresse();
		while((tmp=(StudentenAdresse)objectIn.readObject()) != null)
		{
			sammlung.put(tmp.getMatrikelnummer(),tmp);
		}
	}
	
	protected void finalize()
	{
		try
		{
			objectOut.close();
			objectIn.close();
		}
		catch(Exception e)
		{
			e.getMessage();
		}
	}
}
class StudentenAdresse implements Serializable
{
		private int matrikelnummer;
		private String name;
		private String vorname;
		
		StudentenAdresse(int matrikelnummer,String name, String vorname)
		{
			this.matrikelnummer = matrikelnummer;
			this.name = name;
			this.vorname = vorname;
		}
		StudentenAdresse()
		{
			matrikelnummer = 0;
			name = "unknown";
			vorname = "unknown";
		}
		
		String getName()
		{
			return name;
		}
		
		String getVorname()
		{
			return vorname;
		}
		
		int getMatrikelnummer()
		{
			return matrikelnummer;
		}
		
		void print()
		{
			System.out.println("Initialisiere Ausgabe des Studenten...");
			System.out.println("Vorname: " + vorname);
			System.out.println("Name: " + name);
			System.out.println("Matrikelnummer: " + matrikelnummer);
			System.out.println("Ausgabe beendet.");
			System.out.println();
		}
}
```


----------



## javimka (3. Jan 2010)

Der Fehler ist wirklich subtil 

Die innere Klasse StudentenAdresse ist nicht static! Dadurch wird, wann immer ein Objekt davon verwendet wird, das Objekt der äusseren Klasse benötigt. Und das ist nicht Serializable ^^

Schreibe [c]static class StudentenAdresse implements Serializable[/c] und das Problem ist vom Tisch. Dafür gibts jetzt ne NullpointerException, weil s2 noch keine Adressen aufgenommen hat


----------



## Tenori (3. Jan 2010)

Ah jetzt geht das schonmal, du hast recht, danke.
Eigentlich führe ich ja im Konstruktor die load()-Methode aus, also sollte doch eigentlich keine NullpointerException kommen, oder?
Weil ich automatisch der neuen HashMap in s2 die Objekte aus der "Studenten.txt" zuweise, 
aber du hast Recht, es kommt eine NullpointerException, was is an der Methode load() falsch?

Grüße


----------



## javimka (3. Jan 2010)

Ändere im Konstruktor mal [c]e.getMessage();[/c] zu [c]e.printStackTrace();[/c]. Dann siehst du nämlich, dass das eigentliche Problem eine EOFExeption ist, die in load() auftaucht.
Ausserdem solltest du nicht vergessen, deine Streams immer mit close() zu schliessen.


----------



## Tenori (3. Jan 2010)

Stimmt, dann kriege ich als Fehlermeldung:

```
java.io.EOFException
	at java.io.ObjectInputStream$BlockDataInputStream.peekByte(Unknown Source)
	at java.io.ObjectInputStream.readObject0(Unknown Source)
	at java.io.ObjectInputStream.readObject(Unknown Source)
	at StudentenVerwaltung.load(StudentenVerwaltung.java:102)
	at StudentenVerwaltung.<init>(StudentenVerwaltung.java:62)
	at Test.main(Test.java:20)
```

Was bedeutet das? "Signals that an end of file or end of stream has been reached unexpectedly during input. " heißt das, das in der Datei nix drinsteht, und deswegen ein Fehler kommt(sprich der Fehler bei save() liegt), oder is das, weilich nicht die close()-Methode der Streams aufrufe?
Bzw. ich rufe ja die close()-Methode in der finalize-Methode der Klasse StudentenVerwaltung auf, reicht das nicht?

Grüße,

PS: Super Forum hier, kriegt man immer sehr schnell Hilfe!

Edit: Das Programm funktioniert jetzt, habe die close()-Methoden einfach direkt in der save und der load methode aufgerufen..
Trotzdem krieg ich noch eine EOFException, aber trotzdem funktioniert dann das Laden, ich kriege bei s2 zumind. keine Fehlermeldung mehr, und er gibt die auch aus.. Komisch


----------



## javimka (3. Jan 2010)

Ehrlich gesagt, blicke ich auch nicht ganz durch. Aber close solltest du schon vorher ausrufen, nicht erst in finalize. sonst liesst du aus dem File bevor das der schreibende Strom geschlossen ist.


----------



## Tenori (3. Jan 2010)

Okay, danke dir. Ich belasse es jetzt dabei, es funktioniert ja alles wie gesollt, auch wennic nicht verstehe, wieso trotzdem eine EOFException ausgegeben wird.. Naja was solls,

Schönen Abend noch


----------

