Kiedy i dlaczego jednostki JPA powinny wdrożyć interfejs Serializable?

151

Pytanie jest w tytule. Poniżej opisałem tylko niektóre z moich przemyśleń i spostrzeżeń.

Kiedy miałem bardzo prosty model domeny (3 tabele bez żadnych relacji), wszystkie moje encje NIE implementowały Serializable.

Ale kiedy model domeny stał się bardziej złożony, otrzymałem RuntimeException, który powiedział, że jedna z moich jednostek nie zaimplementowała Serializable.

Używam Hibernate jako implementacji JPA.

Zastanawiam się:

  1. Czy jest to wymóg / zachowanie specyficzne dla dostawcy?
  2. Co dzieje się z moimi jednostkami możliwymi do serializacji? Czy powinny być możliwe do serializacji w celu przechowywania lub przenoszenia?
  3. W którym momencie konieczne jest umożliwienie serializacji mojej jednostki?
rzymski
źródło

Odpowiedzi:

59

Zwykle dzieje się tak, gdy mieszasz zapytania HQL i natywne SQL. W HQL, Hibernacja odwzorowuje typy, które przekazujesz, na wszystko, co DB rozumie. Po uruchomieniu natywnego języka SQL mapowanie należy wykonać samodzielnie. Jeśli tego nie zrobisz, domyślne mapowanie polega na serializacji parametru i wysłaniu go do bazy danych (w nadziei, że to zrozumie).

Aaron Digulla
źródło
To nie wyjaśnia, dlaczego po prostu „może jak” Zobacz odpowiedź poniżej od Bozho
chrips
czy to oznacza, że ​​jednostka zostanie zapisana w bazie danych bez implementacji interfejsu serializowalnego?
Hanumantha_3048092,
@ Hanumantha_3048092 Tak. Mapowanie jednostek i Serializableto dwie różne koncepcje.
Aaron Digulla
@AaronDigulla Czy możesz to wyjaśnić na przykładzie lub pseudokodzie.
sdindiver
110

Zgodnie ze specyfikacją JPA:

Jeśli instancja jednostki ma być przekazywana według wartości jako obiekt odłączony (np. Przez zdalny interfejs), klasa jednostki musi implementować interfejs Serializable.

„JSR 220: Enterprise JavaBeansTM, wersja 3.0 Java Persistence API wersja 3.0, ostateczne wydanie 2 maja 2006”

Conor
źródło
14
(+1) patrzenie na specyfikację jest zawsze owocne
Bozho
20
Nie rozumiem, dlaczego ma to tyle pozytywnych głosów. OP mówi, że nie było to wymagane, gdy model był prostszy. Wysyłanie obiektów zdalnie za pośrednictwem serializacji Java ZAWSZE wymagałoby, aby obiekty były możliwe do serializacji, niezależnie od ich złożoności. Oczywiście nie jest to przypadek użycia OP.
Robin
Nie jestem pewien co do hibernacji, ale w przypadku innych dostawców JPA istnieją operacje, które wymagają od dostawcy wykonania kopii jednostki (obiektu). Serializablemógłby być w tym pomocny i bardziej konsekwentny w kontekście wytrwałości niż Cloneablena przykład.
JimmyB,
Ta odpowiedź to tylko zrzut informacji i wcale nie pomaga komuś zrozumieć, dlaczego.
chrips
59

Potrzebujesz swoich encji, Serializablejeśli chcesz przesłać je przez sieć (serializować je do innej reprezentacji), przechowywać je w sesji http (która z kolei jest serializowana na dysk twardy przez kontener serwletów) itp.

Tylko ze względu na wytrwałość Serializablenie jest potrzebny, przynajmniej w przypadku Hibernate. Ale najlepiej jest je robić Serializable.

Bozho
źródło
2
Nie wiem, może moje istoty są gdzieś niejawnie przenoszone. Używam hibernate + spring + jsf i Tomcat. Gdzie w tym łańcuchu może mieć miejsce przenoszenie?
Roman
Na przykład @Roman bieżący użytkownik (który może być bytem) i wszystkie powiązane z nim encje mogą znaleźć się w sesji, która, jak mówi Bozho, może zostać serializowana na dysk przez kontener serwletów.
OrangeDog
TO jest najlepsza odpowiedź „dlaczego i kiedy”! Jasny! Dziękuję
chrips
13

Zgodnie z dokumentacją hibernacji , używając adnotacji @JoinColumn:

Ma jeszcze jeden parametr o nazwie referencedColumnName. Ten parametr deklaruje kolumnę w jednostce docelowej, która będzie używana do łączenia. Zwróć uwagę, że w przypadku używania referencedColumnNamedo kolumny klucza innego niż podstawowy, skojarzona klasa musi być Serializable.

aman maharjan
źródło
8

Jako uzupełnienie miłej odpowiedzi Conora, który odniósł się do specyfikacji JSR-317. Zazwyczaj projekty EAR składają się z modułu EJB z EJB udostępnionymi przez zdalny interfejs. W tym jednym przypadku konieczne jest umożliwienie serializacji komponentów bean encji, ponieważ są one zagregowane w zdalnym komponencie EJB i zbudowane tak, aby można je było łączyć za pośrednictwem sieci.

Projekt wojenny JEE6 bez CDI: może zawierać EJB Lite wspierany przez nie-serializowalne jednostki JPA.

Projekt wojenny JEE6 z CDI: Fasole, które używają zakresu sesji, aplikacji lub konwersacji, muszą być serializowalne, ale komponenty bean używające zakresu żądania nie muszą być serializowane. W ten sposób bazowa fasola encji JPA - jeśli w ogóle - miałaby tę samą semantykę.

Sym-Sym
źródło
7

Jeśli mówimy tylko o wytrwałości, Serializablenie jest to potrzebne, ale najlepszą praktyką jest tworzenie bytów Serializable.

Jeśli eksponujemy domain/ entitiesobiekty bezpośrednio wystawiane na warstwę prezentacji, to zamiast używać DTO, w takim przypadku musimy zaimplementować Serializable. Te obiekty domeny mogą być przechowywane w HTTPSessioncelu buforowania / optymalizacji. Sesja http może być serializowana lub klastrowana. Jest to również wymagane do przesyłania danych między JVMokolicznościami.

Kiedy używamy DTOdo oddzielenia warstwy trwałości od warstwy usług, oznaczanie obiektów domeny jako Serializablenieproduktywne i naruszałoby „ encapsulation”. Wtedy staje się anty-wzorcem.

Identyfikatory złożone

Klasa klucza podstawowego musi być możliwa do serializacji.

Modele POJO

Jeśli instancja jednostki ma być używana zdalnie jako obiekt odłączony, klasa jednostki musi implementować Serializableinterfejs.

Pamięć podręczna
Ponadto, jeśli wdrażasz clustereddrugi poziom, cacheTwoje encje muszą być serializable. Identyfikator musi być, Serializableponieważ jest to wymóg JPA, ponieważ identifiermoże być używany jako klucz dla wpisu pamięci podręcznej drugiego poziomu.

A kiedy serializujemy jednostki, upewnij się, że podajesz jawny serialVersionUIDmodyfikator dostępu prywatnego. Ponieważ jeśli serializableklasa nie deklaruje jawnie a serialVersionUID, wówczas środowisko wykonawcze serializacji obliczy serialVersionUIDwartość domyślną dla tej klasy na podstawie różnych aspektów tej klasy, zgodnie z opisem w specyfikacji serializacji obiektów Java (TM). serialVersionUIDObliczenia domyślne są bardzo wrażliwe na szczegóły klasy, które mogą się różnić w zależności od implementacji kompilatora i mogą w związku z tym powodować nieoczekiwane InvalidClassExceptionspodczas deserializacji.

Ankur Singhal
źródło
6

Uważam, że twój problem jest związany z posiadaniem pola typu złożonego (klasy), które nie jest opatrzone adnotacjami. W takich przypadkach domyślną obsługą będzie przechowywanie obiektu w jego serializowanej postaci w bazie danych (co prawdopodobnie nie jest tym, co chciałeś zrobić) Przykład:

Class CustomerData {
    int getAge();
    void setAge(int age);
}

@Entity
Class Customer {
  CustomerData getCustomerData();
  void setCustomerData(CustomerData data)
}

W powyższym przypadku CustomerData zostanie zapisane w polu tablicy bajtów w bazie danych w postaci serializowanej.

Avner Levy
źródło
5

Specyfikacja JPA

Zgodnie ze specyfikacją JPA jednostka powinna być wdrażana Serializabletylko wtedy, gdy musi zostać przekazana z jednej maszyny JVM do drugiej lub jeśli jednostka jest używana przez Stateful Session Bean, który musi zostać pasywowany przez kontener EJB.

Jeśli instancja jednostki ma być przekazywana przez wartość jako obiekt odłączony (np. Przez zdalny interfejs), klasa jednostki musi implementować ten Serializableinterfejs.

Hibernować

Hibernacja wymaga tylko, aby atrybuty jednostki były Serializable, ale nie samej jednostki.

Jednak implementując specyfikację JPA, wszystkie wymagania JPA dotyczące Serializablepodmiotów dotyczą również Hibernate.

Kocur

Według Tomcat documantation , te HttpSessionatrybuty muszą być również Serializable:

Za każdym razem, gdy Apache Tomcat jest normalnie zamykany i restartowany lub gdy wyzwalane jest przeładowanie aplikacji, standardowa implementacja Managera podejmie próbę serializacji wszystkich aktualnie aktywnych sesji do pliku dyskowego znajdującego się za pośrednictwem atrybutu pathname. Wszystkie takie zapisane sesje zostaną następnie deserializowane i aktywowane (zakładając, że w międzyczasie nie wygasły) po zakończeniu ponownego ładowania aplikacji.

Aby pomyślnie przywrócić stan atrybutów sesji, wszystkie takie atrybuty MUSZĄ implementować interfejs java.io.Serializable.

Tak więc, jeśli jednostka jest przechowywana w formacie HttpSession, powinna zaimplementować Serializable.

Vlad Mihalcea
źródło
4

Klasy muszą implementować Serializable, jeśli chcesz je serializować. Nie jest to bezpośrednio związane z JPA, a specyfikacja JPA nie wymaga, aby jednostki były serializowane. Jeśli Hibernate naprawdę narzeka na to, przypuszczam, że jest to błąd Hibernacji, ale przypuszczam, że bezpośrednio lub pośrednio robisz coś innego z bytami, które wymagają, aby były możliwe do serializacji.

jarnbjo
źródło
3

Zapoznaj się z http://www.adam-bien.com/roller/abien/entry/do_jpa_entities_have_to, gdzie jest napisane: Implementacja java.io.Serializable jest po prostu wymagana do przesyłania danych przez IIOP lub JRMP (RMI) między instancjami JVM. W przypadku czystej aplikacji internetowej obiekty domeny są czasami przechowywane w HTTPSession w celu buforowania / optymalizacji. Sesja http może być serializowana (pasywacja) lub klastrowana. W obu przypadkach cała zawartość musi być serializowalna.

Arun K.
źródło
1

zdalne trafienie przy użyciu postman, ajax lub angular js itp ..... może spowodować cykl powtarzania z wyjątkiem StackOverflow z Jackson szybciejXml. Dlatego lepiej jest użyć serializatora.

Tamil
źródło
1
  1. W którym momencie konieczne jest umożliwienie serializacji mojej jednostki?

Wdrożenie ehcache z magazynem dyskowym jako pamięcią podręczną drugiego poziomu (tj. Przy użyciu @Cacheableadnotacji na jednostce lub metodzie repozytorium / usługi) wymaga Serializable, w przeciwnym razie pamięć podręczna nie powiedzie się ( NotSerializableException), aby zapisać jednostkę do pamięci podręcznej dysku.

Michał
źródło
0

Jest to również błąd, który pojawia się, gdy przekazujesz niepoprawnie wpisany identyfikator jako drugi parametr do czegoś takiego jak em.find () (tj. Przekazując samą jednostkę zamiast jej identyfikatora). Nie uważam jeszcze za konieczne, aby faktycznie zadeklarować jednostki JPA jako możliwe do serializacji - nie jest to naprawdę konieczne, chyba że używasz referencedColumnName zgodnie z opisem amana.

Amalgovinus
źródło
0

gdy jednostki JPA są używane jako parametry lub zwracają wartości przez zdalne operacje EJB

SAR
źródło