2015-01-22 4 views
8

Wie ein kleines Projekt habe ich versucht, eine kleine Sache zu machen, die serialisierte Lambdas (lokal oder von einem FTP) liest und ihre Lauffunktionen als Teil eines Tests zum Experimentieren mit Dateizuordnungen in Windows (dh das Öffnen bestimmter Dateitypen öffnet sie mit einem bestimmten Programm) und was auch immer, aber egal was ich versuche, scheint es nie richtig zu deserialisieren.Lambda nicht deserialisieren

Das Lambda wurde wie so

erklären
Runnable r = (Runnable & Serializable)() -> { 
    // blah blah 
    // made sure not to capture anything 
}; 

und serialisiert einen Outputstream durch ein [n optional] BufferedOutputStream von einem Object ohne Problem gewickelt werden. Wenn es jedoch [in einem anderen Projekt] deserialisiert wird, schlägt es fehl und sagt, dass es die umschließende Klasse, die den Code für die Serialisierung enthielt, nicht finden konnte. Ich habe verschiedene Dinge versucht, wie sie in eine serialisierbare Klasse (w/serialVersionUID = 0L für Testzwecke) zu wickeln oder eine Schnittstelle zu definieren, die Runnable und Serializable erweitert, aber ohne Erfolg.

Ja, ich bin mir bewusst, dass das Serialisieren von Lambdas nicht wirklich gute Übung ist (aber das wird uns gesagt), aber ich bin mir nicht sicher, wie ich Funktionen und Subroutinen in etwas umwandeln kann, das ich als Datei speichern kann in einem FTP. Wenn das überhaupt nicht der richtige Weg ist, sag es.

Oh, ich benutze Eclipse Luna von was auch immer die neueste Version ist.

Edit:

entserialisierten wie so

File f = new File(somePath); 
FileInputStream fish = new FileInputStream(f); 
BufferedInputStream bos = new BufferedInputStream(fish); // not really necessary 
ObjectInputStream ois = new ObjectInputStream(bos); 
Runnable r = (Runnable) ois.readObject(); 
ois.close(); 
r.run(); 
+0

Warten Sie, um eine Methode zu serialisieren? –

+0

Methodenobjekte sind nicht serialisierbar. Ich spreche von einem Runnable Lambda. –

+1

Können Sie uns Ihren Serialisierungs-/Deserialisierungscode zeigen? –

Antwort

11

Sie können ein Objekt nicht deserialisieren, wenn die Klasse es nicht definiert. Dies hat sich bei Lambda-Ausdrücken nicht geändert.

Lambda-Ausdrücke sind etwas komplexer, da ihre generierte Laufzeitklasse nicht die Klasse ist, die sie definierte, sondern ihre definierende Klasse diejenige ist, die den Code des Körpers von Lambda und im Falle serialisierbarer Lambdas eine Deserialisierungs-Unterstützungsmethode enthält wird zur Validierung und erneuten Instantiierung der Lambda-Instanz aufgerufen.

Siehe SerializedLambda:

Implementors von serializable lambdas, wie Compiler oder Language Runtime-Bibliotheken, erwartet werden, um sicherzustellen, dass Fälle richtig deserialisieren. Eine Möglichkeit, dies zu tun, besteht darin, sicherzustellen, dass die Methode writeReplace eine Instanz SerializedLambda zurückgibt, anstatt zuzulassen, dass die Standardserialisierung fortgesetzt wird.

SerializedLambda eine readResolve Methode verfügt, die $deserializeLambda$(SerializedLambda) in der Capturing-Klasse aufgerufen für einen (möglicherweise privat) statische Methode sieht, ruft das mit sich selbst als erstes Argument und gibt das Ergebnis zurück. Lambda-Klassen, die $deserializeLambda$ implementieren, sind verantwortlich für die Validierung, dass die Eigenschaften des SerializedLambda mit einem tatsächlich von dieser Klasse erfassten Lambda konsistent sind.

Also selbst wenn die Instanz nicht innerhalb der definierenden Klasse (zB im Fall eines Verfahrens Bezug auf ein Verfahren außerhalb dieser Klasse) auf ein Syntheseverfahren mit Bezug wurde, erfordert Deserialisierung noch die $deserializeLambda$ für die Richtigkeit der Validierung Beispiel, absichtlich.


In Bezug auf die „good practice“ lambdas von Serialisierung, bedenken Sie, dass Lambda-Ausdrücke Verhalten, nicht Zustand einzukapseln. Speicherverhalten bedeutet immer, nur eine Art von Referenz zu speichern und den Code, der es wiederherstellen soll, zu benötigen, um das zugehörige Verhalten implementiert zu haben. Das würde genauso gut funktionieren, wenn Sie sich gerade auf das beabsichtigte Verhalten durch einen symbolischen Namen bezogen oder einfach nur gespeichert haben, z. zugehörige enum Werte.

Mehr über die Auswirkungen von Serialisierung Lambdas wird in this question erklärt.

+0

Was könnte die "Standard" -Methode sein, um zustandsunabhängige Subroutinen zu speichern, anstatt, was ich tue? –

+1

Es gibt keinen Standardweg, da normalerweise keine Routinen, sondern Daten gespeichert werden. Wenn Sie Verhalten speichern wollen, müssen Sie entweder die definierende Klasse auf der wiederherstellenden Site verfügbar machen oder Code wirklich speichern, entweder als Byte-Code oder als Ausdruck "String", der analysiert werden muss. – Holger

+0

Welcher Weg ist weniger schlecht? Wie kann man Java-Anweisungen/Ausdrücke zur Laufzeit analysieren oder direkten Bytecode speichern, je nachdem, welcher der bessere Weg ist? Ich fühle mich, als ob das nicht wirklich gute Praxis ist, sondern nur Möglichkeiten zu lernen, Java-spezifische Anweisungen von Programm zu Programm zu übergeben, um Prozess zu verarbeiten. –

4

Wenn Sie ein Objekt deserialisieren, der Code die Deserialisierung tun über die Klasse des serialisierten Objekts kennen. Sie können kein beliebiges Lambda serialisieren und es in einer anderen Codebasis deserialisieren.

Der Serialisierungs- und Deserialisierungscode muss sich mehr oder weniger in derselben Codebasis befinden oder mindestens eine Abhängigkeit vom Code mit dem ursprünglichen Lambda aufweisen.