Java – elementarz serializacji

post_img

Temat serializacji obiektów w języku Java jest z pozoru trywialny : wystarczy zaimplementować malutki interfejsik – i gotowe!  Czasem jednak to, co wydaje się tak oczywiste, przysparza inżynierom pracy na wiele dni…

Za większością publikacji, więc również i za tą, kryje się głębsza historia opowiadająca o pewnym systemie informatycznym zaimplementowanym w języku Java, który można opisać nośnymi przymiotnikami, takimi jak „skalowalny”, „rozproszony”, „wielowarstwowy” itd.

Jak powszechnie wiadomo (a jeżeli nie, to od tej chwili będzie), inżynierowie, którzy rozpraszają systemy 🙂 , bardzo często stosują mechanizmy związane z replikacją danych.  Takim mechanizmem jest z całą pewnością rozproszony bufor (cache) obiektów Java i to na nim będziemy się teraz skupiać.

Stosując mechanizmy buforowania zawsze dbamy o to, aby obiekty były „serializowalne”, ponieważ zawartość bufora może być zapisywana również na dyski lub do baz danych.  W przypadku bufora rozproszonego (tzn. takiego,  który dba o to aby każdy z systemów miał taką samą zawartość bufora) obiekty są przesyłane przez sieć, co również wymusza serializację.

Tyle tytułem wstępu – teraz konkrety.

Implementacja

  • Rozwijamy system lokalnie (np. serwer aplikacji na własnej stacji roboczej).
  • Od początku zakładamy stosowanie rozproszonego bufora.
  • Implementujemy złożoną strukturę obiektów (wiele poziomów dziedziczenia, liczne asocjacje).
  • Implementujemy serializowalność obiektów, które chcemy buforować.
  • Testujemy wszystko, bufory są wypełniane, odczyt i zmiany są możliwe – działa! 🙂

Skalowanie

  • Uruchamiamy napisany system na kilku maszynach.
  • Testujemy wszystko, bufory są wypełniane, odczyt i zmiany są możliwe i…  klops 🙁 – bufor nie synchronizuje się prawidłowo z innymi maszynami w sieci.

Ratowanie

  • Gdzie popełniliśmy błąd ???
  • Może to implementacja bufora jest niedojrzała – ma wiele błędów, które nie zostały poprawione przez producenta?
  • Nie działa replikacja i tyle – pewnie trzeba zainstalować nową wersję bufora [standardowa akcja inżyniera numer 1 🙂 ].
  • Sprawdzamy: wszystko, co chcemy trzymać w cache,  implementuje java.io.Serializable – czyli jest ok.

Problem

  • Szperamy w logach i w kodzie (duuużo klas, konfiguracji itp. , itd.)  i… tu pojawia się pytanie: dlaczego błędy dotyczą klas,  które dziedziczą po innych ?

Więc tak na prawdę co poszło nie tak? Popatrzmy na fragment pseudokodu Java:

Zaprojektowaliśmy klasy, z których jedną (Bomber) chcemy zapisywać do bufora:

    class Airplane {
        public String name;
        public Integer enginesCount;
    }

    class Bomber extends Airplane implements Serializable{
        public Integer bombCount;
    }

Teraz zapiszemy je do pliku mechanizmami dostępnymi w J2SE:

    Bomber b = new Bomber();
    b.name = "Sztukas";
    b.enginesCount = 1;
    b.bombCount= 4;
    ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("bombowiec.obiekt"));
    out.writeObject(b);
    out.close();

Skoro już zapisaliśmy obiekt, to teraz go odczytajmy i wypiszmy w konsoli, co tam „siedzi”:

    ObjectInputStream in = new ObjectInputStream(new FileInputStream("bombowiec.obiekt"));
    Bomber b = (Bomber) in.readObject();
    in.close();
    System.out.println("name="+b.name);
    System.out.println("enginesCount="+b.enginesCount);
    System.out.println("bombCount="+b.bombCount);

Oto co pokazała konsola:

    name=null
    enginesCount=null
    bombCount=4

Czy to ten sam bombowiec? Oczywiście nie, a co zrobić, żeby to był „nasz”?
Proszę bardzo, modyfikujemy projekt naszych samolotów:

    class Airplane  implements Serializable {
        public String name;
        public Integer enginesCount;
    }

    class Bomber extends Airplane {
        public Integer bombCount;
    }

Jest różnica? Proszę sprawdzić własnoręcznie.
Uhm, przecież jaka ta Java jest prosta…

Dodaj komentarz

Twój adres email nie zostanie opublikowany. Pola, których wypełnienie jest wymagane, są oznaczone symbolem *