Freitag, 15. April 2011

 

Serialisierungsprobleme mit RMI (PR: 5A, 5B)

Remote Method Invocation funktioniert nur für Objekte, welche serialisiert werden können (die also das Interface Serializable implementieren). Wird innerhalb eines Objekts, welches über RMI gebunden werden soll, eine Referenz auf ein nicht serialisierbares Objekt benötigt, so bekommt man immer eine Exception der Art (z.B. für RandomAccessFile):
sun.rmi.registry.RegistryImpl_Stub.rebind(Unknown Source)
java.rmi.Naming.rebind(Naming.java:177)
rmi.Server.run(Server.java:43)
rmi.Server.main(Server.java:68)
error marshalling arguments; nested exception is: 
 java.io.NotSerializableException: java.io.RandomAccessFile
RandomAccessFile ist nicht serialisierbar, weil der innere Zustand so eines Objekts von der Laufzeitumgebung (Betriebssystem, Dateisystem, etc.) abhängt. Eine Referenz auf ein RandomAccessFile-Objekt muss als transient deklariert werden. Wenn nötig, dann muss der Zustand selbst gespeichert bzw. wiederhergestellt werden, z.B. in Form des Dateinamens und der Position innerhalb der Datei.
Dazu kann man die Methoden des Interfaces Serializable implementieren:
private void writeObject(java.io.ObjectOutputStream out)
    throws IOException
private void readObject(java.io.ObjectInputStream in)
    throws IOException, ClassNotFoundException;
private void readObjectNoData() 
    throws ObjectStreamException;
Für die Zwecke der Data-Klasse genügen die ersten beiden Methoden. Folgender Ausschnitt aus der Data-Klasse soll dies verdeutlichen:
public class Data implements DB, Header, Serializable {

    private static final long serialVersionUID = -8958941842720498616L;
    private transient RandomAccessFile database;
    private String filename;
    private transient Logger log = Logger.getLogger(LOGURL);
    private DBHeader header;
    private TreeMap data;
    private int lastDeleted = -1; // zuletzt gelöschter Datensatz

    private void writeObject(ObjectOutputStream stream) throws IOException {
        stream.defaultWriteObject();
        stream.writeLong(database.getFilePointer());
    }

    private void readObject(ObjectInputStream stream) throws IOException {
        try {
            stream.defaultReadObject();
        } catch (ClassNotFoundException e) {
            String msg = "Unable to find class";
            if (e.getMessage() != null)
                msg += ": " + e.getMessage();
            throw new IOException(msg);
        }
        database = new RandomAccessFile(filename, "rw");
        database.seek(stream.readLong());
        log = Logger.getLogger(LOGURL);
    }

//... weiterer Code entfernt
}
Hier ist auch der Logger transient, da auch der Logger vom Dateisystem abhängt und nicht serialisiert werden kann.

Labels: ,


Kommentare:

Kommentar veröffentlichen

Abonnieren Kommentare zum Post [Atom]





<< Startseite

This page is powered by Blogger. Isn't yours?

Abonnieren Posts [Atom]