Problem z zapisem całego obiektu do pliku.

0

Witam. Mam dość spory problem. W moim programie, który jest bazą danych płyt muzycznych chciałem zrobić zapis i odczyt obiektu z pliku zewnętrznego.

Hierarchia wygląda następująco: Najpierw jest klasa abstrakcyjna AbstractMusicList, która implementuje interfejs IMusicList.
Tam mamy metody:

public void saveToFile(IMusicList l) throws IOException {           
		ObjectOutputStream file = new ObjectOutputStream(new FileOutputStream(
			"baza.dta"));
		file.writeObject(l);
		file.flush();
		file.close();
	}
		
	public static IMusicList restore(String name) throws IOException, 
			ClassNotFoundException {
		ObjectInputStream in = new ObjectInputStream(new FileInputStream(name));
		IMusicList temp = (IMusicList) in.readObject();
		in.close();
		
		return temp;
	}

Następnie dziedziczą z tej klasy abstrakcyjnej dwie klasy zwykłe MusicLIFOList i MusicFIFOList.
Nie ma w ich ciałach żadnych przysłonięć tych metod, bo wiadomo że dziedziczenie wystarczy.

Mam też klasę Controller (ponieważ mój projekt jest oparty o MVC), która zarządza tym wszystkim.
Wygląda to mniej więcej tak:

 
...
public class Controller {
     private IMusicList list;     // bo tu jest zwracana implementacja interfejsu za pomocą klasy 
                                          factory, czyli MusicLIFOList lub FIFO

...
     list = AbstractMusicList.restore(win.txt1.getText());           // wywołanie dla odczytu
...
     list.saveToFile(list);                                                     //wywołanie dla zapisu

Wydaje się, że wszystko jest ok, a jednak gdy przejechałem debuggerem okazało się, że zmienna 'file' ma w sobie nulla.
Co się dzieje?
Jest to tym bardziej dziwaczne, że wcześniej, kiedy jeszcze nie używałem klasy abstrakcyjnej, a MusicLIFOList i MusicFIFOList miały w sobie całość ciała wszystko było ok.

Dziwna sprawa.

0

A czy nie lecą exceptiony? czy obiekty są serializowane?

0

Napisz metodę porządnie

public void saveToFile(IMusicList l) {           
                try
                {
                ObjectOutputStream file = new ObjectOutputStream(new FileOutputStream(
                        "baza.dta"));
                file.writeObject(l);
                file.flush();
                file.close();
                }
                catch(Exception e)
                {
                     e.printStackTrace();
                } 
        }

to się dowiesz czemu file jest null.

0

Tak . Wyłapywanie Exceptiona nic nie dalo, ponieważ on nie występuje. Jak napisałem wyżej metoda rzuca IOException, które jest wyłapywane ewentualnie w controllerze. Ale jak pisałem nie występuje żaden wyjątek.

Klasy dziedziczące z abstract listy implementują serializable, a także elementy Music Item, które są magazynowane w liście.

Jak na razie nic nie wiadomo.

0

Nie ma możliwości, żeby file było null, cokolwiek by się nie stało. Napisz dokładnie, co się dzieje po wywołaniu saveToFile.
Inna sprawa, że metody saveToFile i restore nie powinny być w AbstractMusicList, tym bardziej jako niestatyczne. Zapis list.saveToFile(list) jest lekko bez sensu.

0

Wstawiam cały log z debuggera dla zmiennych przy file.close();

 
this	MusicLIFOList  (id=40)	          //te listy zawierają to co powinny
l	MusicLIFOList  (id=40)	

file	ObjectOutputStream  (id=43)	
	bout	ObjectOutputStream$BlockDataOutputStream  (id=54)	
	curDesc	null	
	curObj	null	
	curPut	null	
	debugInfoStack	null	
	depth	0	
	enableOverride	false	
	enableReplace	false	
	handles	ObjectOutputStream$HandleTable  (id=68)	
		loadFactor	3.0	
		next	 (id=73)	
		objs	Object[10]  (id=75)	
		size	2	
		spine	 (id=77)	
		threshold	30	
	primVals	 (id=70)	
	protocol	2	
	subs	ObjectOutputStream$ReplaceTable  (id=71)	
		htab	ObjectOutputStream$HandleTable  (id=78)	
		reps	Object[10]  (id=79)	

Metoda restore jest statyczna.
Dlaczego tego typu metody nie powinny być w klasach abstrakcyjnych i gdzie w takim razie powinny się znaleźć?

A zapis list.saveToFile(list); nie wydaje mi się jakiś mocno nielogiczny. Po prostu wywołujemy metodę saveToFile obiektu list i ten obiekt przekazujemy tam. Nie mogłem zrobić tego za pośrednictwem this, bo metoda jest w klasie abstrakcyjnej. Choć powiem, że nawet po przeniesieniu całej metody do ciał MusicFIFO i IFOList i zapisaniu tego jako writeObject(this); też nic to nie dało.

Czy też powyższy zapis może być przyczyną moich problemów?

//EDIT

Zauważyłem, że dla zmiennej file w polu handles -> objs mamy komórki [0] , [1], [2] itd.

w [0] jest - MusicLIFOList: static final long serialVersionUID = 6590325191389748831L; czyli chyba cały obiekt, a
w [1] jest Title_Author_Year_Genre_Rating
a_a_a_a_a - czyli toString tegoż

reszta to null'e.

primVals ma pustą tablicę.

W czym więc problem? W restore?

Powiem też, że gdy po zapisie otwieram plik baza.dta notatnikiem i porównuję to z tym samym plikiem, ale zapisanym poprawnie, to zawartość jest zubożona.
Czyli jednak trzeba szukać w saveToFile.

0

Metoda restore jest statyczna.
Dlaczego tego typu metody nie powinny być w klasach abstrakcyjnych i gdzie w takim razie powinny się znaleźć?
W sumie mogą, chodzi mi głównie o saveToFile, które nie jest statyczne, a jednocześnie przyjmuje obiekt swojej klasy - niech będzie albo statyczne, albo bezargumentowe.

Nie mogłem zrobić tego za pośrednictwem this, bo metoda jest w klasie abstrakcyjnej.
Mogłeś.

Z loga nie wynika, że file jest nullem. Nadal nie wiem, co dzieje się po wywołaniu metody - nie zapisuje się, zapisuje się po części, nie chce się potem odczytać, a może wywala IOE, a ty go przechwytujesz i tłumisz?

Powiem też, że gdy po zapisie otwieram plik baza.dta notatnikiem i porównuję to z tym samym plikiem, ale zapisanym poprawnie, to zawartość jest zubożona.
To znaczy, że obiekt udaje się zapisać poprawnie?

0

Czyli mogłem napisać w abstractMusicList:

 
public static void saveToFile(IMusicList l) throws IOException {                  //zapis obiektu do pliku
		ObjectOutputStream file = new ObjectOutputStream(new FileOutputStream(
			"baza.dta"));
		file.writeObject(l);
		file.flush();
		file.close();
	}

lub co dziwniejsze:

 
public void saveToFile() throws IOException {                  //zapis obiektu do pliku
		ObjectOutputStream file = new ObjectOutputStream(new FileOutputStream(
			"baza.dta"));
		file.writeObject(this);
		file.flush();
		file.close();
	}

To pierwsze ma sens, ale to drugie? Zapis dobry?

Sprawa wygląda tak: Po wywołaniu metody tworzy się plik baza.dta o następującej wartości:

 ’ |sr 
MusicLIFOList[u‰Ř3_  xp 

//po przejrzeniu notatnikiem

Ta zawartość to za mało, ponieważ jak pisałem w pierwszym poście, w programie kiedy miałem jeszcze inną strukturę, bez klasy abstrakcyjnej zapis i odczyt działał (oczywiście metody wyglądały tak samo tylko całe ciało abstract listy było w MusicLIFO i FIFO List) i po podejrzeniu pliku baza.dta był on znacznie dluższy.

Czyli zaczyna zapis, ale nie kończy. Wie co to za obiekt, ale wygląda na to że nie zapisuje jego zawartości, czyli MusicItemów (bo je lista przechowuje).

Żadne Exceptiony nie występują.

Jeśli potrzebna jest wartość jakiegoś konkretnego pola w zmiennej w debuggerze to proszę napiszcie, a ja to jeszcze sprawdzę.

Myślałem, że zawartość zmiennej jest w komórce "primVals".

A co z tymi komórkami tablicy w "objs"??

0

To pierwsze ma sens, ale to drugie? Zapis dobry?
To drugie też, rzeczywistym typem obiektu jest podklasa AbstractMusicList i to z nim wiązane jest this.

Myślałem, że zawartość zmiennej jest w komórce "primVals".
A co z tymi komórkami tablicy w "objs"??
primVals to bufor na prymitywy, objs to tablica w klasie HandleTable, mapującej obiekty na ich uchwyty-referencje, ale to tak swoją drogą.

Pokaż definicje tych klas.

0

Już rozgryzłem problem, a mianowicie:

Interfejs IMusicList, który był implementowany do AbstractMusicList - sam nie implementował interfejsu Serializable.

Za to ten interfejs (Serializable) importowały MusicLIFO i FIFO List oraz MusicItem - myślałem że to wystarczy - a tu nie.

Zdziwiłem się tylko lekko, że nie było jakiegoś błędu kompilacji.

No ale jest już w porządku. Dzięki za pomoc :)

0

Na etapie kompilacji nie jest to sprawdzane, bo i jak miałoby być. ObjectOutputStream.writeObject przyjmuje typ Object i ewentualnie sypie NotSerializableException, jeśli obiekt nie implementuje Serializable.

1 użytkowników online, w tym zalogowanych: 0, gości: 1