2015-01-22 13 views
8

Proprio come un piccolo progetto, ho cercato di creare una cosa che legge lambda serializzato (localmente o da un FTP) e invoca le loro funzioni di esecuzione come parte di un test per sperimentare le associazioni di file in Windows (ovvero l'apertura di determinati tipi di file li apre con un determinato programma) e quant'altro, ma non importa quello che provo, non sembra mai deserializzare correttamente.Impossibile deserializzare lambda

La lambda è stato dichiarato in questo modo

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

e serializzato utilizzando un FileOutputStream avvolta da un [n opzionale] BufferedOutputStream avvolto da un ObjectOutputStream senza alcun problema. Tuttavia, quando deserializzato [in un progetto diverso], fallisce, dicendo che non è stato in grado di trovare la classe che contiene il codice per la serializzazione. Ho provato varie cose, come ad esempio il loro wrapping in una classe serializzabile (w/serialVersionUID = 0L a scopo di test) o la definizione di un'interfaccia che estende Runnable e Serializable, ma senza alcun risultato.

Sì, sono consapevole che serializzare lambda non è una buona pratica (o almeno così ci viene detto), ma non sono sicuro di come trasformare funzioni e subroutine in qualcosa che posso memorizzare come file o in un FTP. Se questo non è nemmeno il modo giusto, dillo.

Oh, sto usando Eclipse Luna di qualunque sia l'ultima versione.

Edit:

deserializzato in questo modo

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

In attesa stai provando a serializzare un metodo? –

+0

Gli oggetti metodo non sono serializzabili. Sto parlando di un lambda Runnable. –

+1

Puoi mostrarci il tuo codice di serializzazione/deserializzazione? –

risposta

11

Non è possibile deserializzare un oggetto senza che la classe lo definisca. Questo non è cambiato con le espressioni lambda.

lambda espressioni sono un po 'più complesso come loro classe runtime generato non è la classe che definisce, ma la loro classe che definisce è quella che tiene il codice del corpo del lambda e, in caso di lambda serializable, un metodo di supporto deserializzazione che è chiamato per validare e riattivare l'istanza lambda.

Vedi SerializedLambda:

Implementors di lambda serializzabili, come i compilatori o le librerie di runtime lingua, sono tenuti a garantire che le istanze deserializzare correttamente. Uno dei mezzi per farlo è assicurarsi che il metodo writeReplace restituisca un'istanza di SerializedLambda, piuttosto che consentire la serializzazione predefinita per procedere.

SerializedLambda ha un metodo readResolve che cerca un metodo (possibilmente privato) statico chiamato $deserializeLambda$(SerializedLambda) nella classe cattura, invoca che con se stesso come primo argomento, e restituisce il risultato. Le classi Lambda che implementano $deserializeLambda$ sono responsabili della convalida che le proprietà dello SerializedLambda sono coerenti con un lambda effettivamente catturato da quella classe.

Quindi, anche se l'istanza non si riferiva ad un metodo di sintesi all'interno della classe definendo (ad esempio nel caso di un metodo di riferimento ad un metodo di fuori di questa classe), deserializzazione richiede ancora la $deserializeLambda$ per convalidare la correttezza della esempio, intenzionalmente.


Per quanto riguarda la “buona pratica” di serializzazione lambda, tenere a mente che le espressioni lambda incapsulano comportamento, non lo stato. L'archiviazione del comportamento implica sempre la memorizzazione di una sorta di riferimento e richiede il codice per ripristinarlo, per implementare il comportamento associato. Ciò funzionerebbe anche se ti riferissi semplicemente al comportamento previsto con un nome simbolico o semplicemente memorizzato, ad es. associati valori enum.

Ulteriori informazioni sulle implicazioni di avere lambda serializzabili sono spiegate in this question.

+0

Quale potrebbe essere il modo "standard" di memorizzare subroutine indipendenti dallo stato, se ce ne sono, invece di fare quello che sto facendo? –

+1

Non esiste un modo standard in quanto normalmente non si memorizzano le routine ma i dati. Se si desidera memorizzare il comportamento, è necessario rendere la classe di definizione disponibile sul sito di ripristino o memorizzare realmente il codice, sia come codice byte sia come espressione 'String' che deve essere analizzata. – Holger

+0

Quale via è meno di una cattiva pratica? Inoltre, per quale dei due è il modo migliore per andare, come si fa ad analizzare le dichiarazioni/espressioni Java in fase di runtime o di memorizzare il bytecode diretto? Mi sembra che questa non sia una buona pratica, ma voglio solo imparare come passare le istruzioni specifiche di Java da programma a programma, processo da elaborare. –

4

Quando si deserializzare un oggetto, il codice a fare la deserializzazione deve sapere sulla classe dell'oggetto serializzato. Non è possibile serializzare un lambda arbitrario e deserializzare in un altro codebase.

Più o meno, il codice di serializzazione e deserializzazione deve essere nella stessa base di codice, o almeno deve condividere una dipendenza dal codice contenente il lambda originale.

Problemi correlati