2015-01-22 18 views
8

Tak jak w przypadku małego projektu, próbowałem zrobić małą rzecz, która czyta serializowane lambdy (lokalnie lub z FTP) i wywołuje ich funkcje uruchamiania w ramach testu, aby eksperymentować ze skojarzeniami plików w Windows (np. Otwieranie pewnych typów plików otwiera je z określonym programem) i inne, ale bez względu na to, co próbuję, nigdy nie wydaje się poprawnie deserializować.Nie można deserializować lambda

lambda został uznany podobnie jak

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

i szeregowane stosując FileOutputStream owinięte [N opcjonalnie] BufferedOutputStream owinięty przez ObjectOutputStream bez problemu. Jednak po deserializacji [w innym projekcie], nie powiedzie się, mówiąc, że nie może znaleźć klasy otaczającej, która zawierała kod do serializacji. Próbowałem różnych rzeczy, takich jak owijając je w klasy serializowalne (w/serialVersionUID = 0L do celów testowych) lub definiując interfejs, który rozszerza Runnable i Serializable, ale bezskutecznie.

Tak, zdaję sobie sprawę, że serializacja lambdas nie jest tak naprawdę dobrą praktyką (lub tak nam powiedziano), ale nie jestem pewien, jak zmienić funkcje i podprogramy w coś, co można zapisać jako plik lub na FTP. Jeśli to nawet nie jest właściwa droga, powiedz to.

Och, używam Eclipse Luna jakiejkolwiek najnowszej wersji.

Edit:

rozszeregować jak tak

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

Czekasz, próbujesz serializować metodę? –

+0

Obiekty metod nie są przekształcalne do postaci szeregowej. Mówię o Runnable lambda. –

+1

Czy możesz pokazać nam swój kod serializacji/deserializacji? –

Odpowiedz

11

Nie można deserializować obiektu bez klasy definiującej go. Nie zmieniło się to w przypadku wyrażeń lambda.

Wyrażenia lambdy są nieco bardziej złożone, ponieważ ich wygenerowana klasa środowiska wykonawczego nie jest klasą, która je zdefiniowała, ale ich klasa definiująca to ta, która zawiera kod ciała lambda, a w przypadku serializowalnych lambd, metoda obsługi deserializacji, która jest wywoływana do sprawdzania poprawności i ponownego tworzenia instancji lambda.

Zobacz SerializedLambda:

Twórcy implementacji serializować lambdas, takie jak kompilatory czy bibliotek uruchomieniowych językowych, oczekuje się, aby upewnić się, że przypadki deserializowania prawidłowo. Jednym ze sposobów na to jest zapewnienie, że metoda writeReplace zwraca instancję SerializedLambda, zamiast pozwalać na kontynuowanie serializacji domyślnej.

SerializedLambda ma readResolve metodę, która wygląda na prywatnej (ewentualnie) metodą statyczną o nazwie $deserializeLambda$(SerializedLambda) w klasie przechwytywania, który powołuje się ze sobą jako pierwszy argument i zwraca wynik. Klasy Lambda implementujące $deserializeLambda$ są odpowiedzialne za sprawdzanie, czy właściwości SerializedLambda są zgodne z lambdą faktycznie przechwyconą przez tę klasę.

Więc nawet jeśli instancji nie odniósł się do sposobu syntetycznego wewnątrz klasy definiującej (np w przypadku odniesienia metoda metody poza tą klasą) deserializacji nadal wymaga $deserializeLambda$ do walidacji poprawności przykład, celowo.


chodzi o „dobrych praktyk” z szeregowania lambdy, należy pamiętać, że wyrażenia lambda hermetyzacji zachowanie, a nie państwa. Przechowywanie zachowań zawsze oznacza przechowywanie tylko pewnego rodzaju odwołania i wymaganie kodu, który ma go przywrócić, aby zaimplementować powiązane zachowanie. To też by działało, gdybyś odniósł się do zamierzonego zachowania za pomocą symbolicznej nazwy lub po prostu przechowywanej, np. powiązane wartości enum.

Więcej informacji o konsekwencjach związanych z serializacją lambdas wyjaśniono w this question.

+0

Co może być "standardowym" sposobem przechowywania podprogramów niezależnych od stanu, jeśli takie są, zamiast robić to, co robię? –

+1

Nie ma standardowego sposobu, ponieważ zwykle nie przechowujesz procedur, ale danych. Jeśli chcesz zachować zachowanie, musisz albo uczynić klasę definiującą dostępną na stronie przywracającej, albo naprawdę zapisać kod, albo jako kod bajtu, albo jako wyrażenie 'String', które musi zostać przeanalizowane. – Holger

+0

Który sposób jest mniej złą praktyką? Ponadto, w zależności od tego, który z nich jest lepszym rozwiązaniem, w jaki sposób można analizować wyrażenia Java/wyrażenia w czasie wykonywania lub zapisywać prosty kod bajtowy? Mam wrażenie, że to nie jest dobra praktyka, ale po prostu chcą nauczyć się przekazywać instrukcje specyficzne dla Javy z programu do programu, proces do przetworzenia. –

4

Podczas deserializacji obiektu, kod robi deserializacji musi wiedzieć o klasie odcinkach obiektu. Nie możesz serializować arbitralnej lambda i deserializować go w innej bazie kodu.

W mniejszym lub większym stopniu kod serializujący i deserializujący musi znajdować się w tej samej bazie kodu lub przynajmniej musi współdzielić zależność od kodu zawierającego oryginalną wartość lambda.

Powiązane problemy