Serializacja to proces przekształcania obiektu lub struktury danych w format sekwencyjny, nadający się do przesłania przez sieć lub zapisania w pliku. Proces odwrotny, deserializacja, przywraca dane do pierwotnego stanu. Według MDN Web Docs, serializacja jest niezbędna w każdej komunikacji międzyprocesowej. Serializacja leży u podstaw REST API, buforowania i wymiany danych między komponentami aplikacji.
Najważniejsze
Serializacja to proces przekształcania obiektu znajdującego się w pamięci operacyjnej w liniową sekwencję bajtów lub znaków, którą można przesłać przez sieć, zapisać w pliku lub przekazać innemu procesowi. Bez serializacji niemożliwa jest komunikacja sieciowa, przechowywanie stanu i komunikacja międzyprocesowa.
Serializacja obejmuje dwa przeciwstawne procesy. Proces bezpośredni (serializacja) pakuje dane w format do przesłania. Proces odwrotny (deserializacja) przywraca dane z powrotem do obiektu. Deserializacja jest krytyczna dla bezpieczeństwa: nieprawidłowe dane wejściowe mogą prowadzić do podatności w aplikacji.
W tworzeniu aplikacji mobilnych serializacja jest używana wszechobecnie: wysyłanie zapytań do serwera i przetwarzanie odpowiedzi, zapisywanie stanu aplikacji przy obrocie ekranu, buforowanie danych na dysku i przesyłanie danych między ekranami przez Intent (Android) lub Segue (iOS).
Formaty serializacji dzielą się na tekstowe i binarne. Formatów tekstowych (JSON, XML) są czytelne dla człowieka i nie wymagają narzędzi do przeglądania. Formatów binarnych (Protobuf, FlatBuffers, MessagePack) są bardziej zwarte i szybsze, ale nieczytelne bez deserializacji. Wybór formatu to kompromis między wydajnością a wygodą debugowania.
Oprócz JSON, XML i Protobuf istnieją wyspecjalizowane formaty: FlatBuffers od Google do gier i AR, MessagePack — zwarta binarna alternatywa JSON, Avro od Apache do dużych danych w Kafka, YAML — format konfiguracyjny z obsługą komentarzy.
| Format | Typ | Schemat | Rozmiar | Szybkość |
|---|---|---|---|---|
| JSON | Tekstowy | Opcjonalnie | Średni | Średnia |
| XML | Tekstowy | XSD | Duży | Niska |
| Protobuf | Binarny | Obowiązkowo | Mały | Wysoka |
| FlatBuffers | Binarny | Obowiązkowo | Mały | Maksymalna |
| MessagePack | Binarny | Nie | Mały | Wysoka |
| Avro | Binarny | JSON Schema | Mały | Wysoka |
Serializacja na platformach mobilnych ma swoją specyfikę: ograniczony ruch, słabsze procesory i konieczność zapisywania stanu przy obrotach ekranu. Na Androidzie używane są Gson, Moshi, Kotlinx Serialization. Na iOS — Codable, JSONSerialization, PropertyListEncoder. Właściwy wybór biblioteki krytycznie wpływa na wydajność aplikacji.
Kotlinx Serialization to nowoczesna biblioteka od JetBrains dla Kotlin Multiplatform Mobile. Obsługuje JSON, Protobuf, CBOR i niestandardowe formaty. Generowanie kodu odbywa się na etapie kompilacji przez plugin Kotlin Serialization, co zapewnia wysoką wydajność bez użycia refleksji.
Biblioteka Kotlinx Serialization używa adnotacji @Serializable dla klas i pluginu kompilatora do generowania serializatorów. Zapewnia to wysoką wydajność i bezpieczeństwo typów. Domyślny format to JSON, ale obsługiwane są również inne formaty poprzez dodatkowe moduły.
import kotlinx.serialization.Serializable
import kotlinx.serialization.json.Json
import kotlinx.serialization.encodeToString
import kotlinx.serialization.decodeFromString
@Serializable
data class Project(
val id: Int,
val name: String,
val platforms: List<String>,
val active: Boolean
)
val json = Json {
prettyPrint = true
ignoreUnknownKeys = true
encodeDefaults = true
}
fun main() {
val project = Project(1, "MobileApp",
listOf("Android", "iOS"), true)
// Serializacja
val jsonString = json.encodeToString(project)
// Deserializacja
val restored = json.decodeFromString<Project>(jsonString)
}
Protokół Codable to wbudowany mechanizm serializacji w Swift. Łączy protokoły Encodable (serializacja) i Decodable (deserializacja). JSONEncoder i JSONDecoder automatycznie przetwarzają zagnieżdżone struktury, tablice, wartości opcjonalne i niestandardowe klucze przez CodingKeys.
import Foundation
struct AppConfig: Codable {
let appName: String
let version: String
let features: [String]
let isProduction: Bool
}
let config = AppConfig(
appName: "MyApp",
version: "2.1.0",
features: ["push", "analytics", "offline"],
isProduction: true
)
let encoder = JSONEncoder()
encoder.outputFormatting = [.prettyPrinted, .sortedKeys]
guard let data = try? encoder.encode(config) else { return }
let jsonString = String(data: data, encoding: .utf8)
Wydajność formatów serializacji ocenia się według trzech metryk: rozmiar wiadomości, szybkość serializacji i szybkość deserializacji. Dla aplikacji mobilnych wszystkie trzy są krytyczne: rozmiar wpływa na ruch i czas ładowania, szybkość — na responsywność interfejsu i czas uruchamiania aplikacji.
Protobuf i FlatBuffers pokazują najlepsze wyniki dzięki binarnemu formatowi. FlatBuffers różni się tym, że nie wymaga osobnego etapu deserializacji — dane są odczytywane bezpośrednio z bufora binarnego, co jest idealne dla gier i aplikacji AR z wymaganiem minimalnego opóźnienia. JSON pozostaje najpopularniejszym formatem dla REST API, pomimo gorszej wydajności, ze względu na prostotę i uniwersalność.
| Scenariusz | Rekomendowany format | Powód |
|---|---|---|
| REST API | JSON | Uniwersalność, czytelność, wsparcie |
| Serwisy | Protobuf | Zwartość, szybkość, gRPC |
| Gry / AR | FlatBuffers | Zero-copy, minimalne opóźnienie |
| Big Data | Avro | Zgodność z Kafka i Hadoop |
| Konfiguracja | YAML | Komentarze, czytelność |
| Android layouts | XML | Standard platformowy |
Praktyczne testy na zbiorze 1000 obiektów użytkowników pokazują: Protobuf tworzy wiadomości o rozmiarze 12 KB (JSON — 85 KB, XML — 120 KB). Czas serializacji: Protobuf — 2 ms, JSON — 8 ms, XML — 25 ms. Te liczby czynią formaty binarne preferowanymi dla systemów high-load i aplikacji mobilnych z ograniczonym ruchem.
Przykłady pokazują serializację tego samego obiektu w różnych formatach. Pomaga to wizualnie porównać rozmiar i czytelność. Ten sam obiekt User zostanie zserializowany w JSON, XML i Protobuf — widać wyraźnie, że JSON jest bardziej zwarty niż XML, a Protobuf jest najbardziej zwarty i jednocześnie nieczytelny.
JSON — minimalistyczna składnia, klucze w cudzysłowie, wartości różnych typów. Zajmuje 80 znaków. Czytelność wysoka, struktura wizualna przejrzysta. Nadaje się do API, gdzie ważna jest szybkość tworzenia i debugowania.
XML — każdy element jest owinięty w otwierający i zamykający znacznik. Zajmuje 150 znaków. Czytelność średnia, struktura ścisła. Nadaje się do obiegu dokumentów i systemów wymagających walidacji przez XSD.
Protobuf — binarny, 32 bajty dla tych danych. Nieczytelny — wymaga deserializacji do przeglądania. Minimalny rozmiar czyni go idealnym dla systemów wysokiego obciążenia i aplikacji mobilnych.
{
"id": 42,
"name": "IT Sectr",
"email": "team@itsectr.com",
"role": "admin",
"active": true
}
<user>
<id>42</id>
<name>IT Sectr</name>
<email>team@itsectr.com</email>
<role>admin</role>
<active>true</active>
</user>
Najlepsze praktyki pomagają uniknąć typowych błędów i wybrać odpowiednią strategię serializacji dla projektu. Przestrzeganie tych zaleceń poprawia wydajność, bezpieczeństwo i utrzymywalność kodu.
Bezpieczeństwo serializacji to krytycznie ważny aspekt, szczególnie przy deserializacji danych z niezweryfikowanych źródeł. Ataki na deserializację mogą prowadzić do zdalnego wykonania kodu (RCE), co jest jedną z najniebezpieczniejszych podatności w aplikacjach internetowych i mobilnych. Najbardziej znane przypadki związane są z Java Serializable i Python pickle.
Protobuf i JSON mają wbudowaną ochronę przed takimi atakami, ponieważ działają tylko z danymi, a nie z dowolnymi obiektami. Java Serializable natomiast może przywracać dowolne klasy dostępne w classpath, co czyni go niebezpiecznym do przyjmowania danych z zewnętrznych źródeł. Na Androidzie zaleca się używanie Kotlinx Serialization lub Moshi zamiast standardowej Java Serialization.
Dodatkowe środki bezpieczeństwa: ustaw limit rozmiaru danych wejściowych, waliduj schemat przed deserializacją, nie ufaj Content-Type z nagłówków HTTP, używaj allowlist dla dozwolonych klas. Regularnie aktualizuj biblioteki serializacji, ponieważ podatności w nich są okresowo wykrywane i naprawiane.
Często zadawane pytania
Serializacja przekształca obiekt w sekwencję bajtów, marshaling przesyła dane między różnymi przestrzeniami adresowymi z zachowaniem typów i struktury. Marshaling obejmuje serializację jako część procesu, ale może również obejmować kodowanie referencji i zarządzanie pamięcią.
FlatBuffers od Google zapewnia maksymalną szybkość dzięki zero-copy deserializacji — dane są odczytywane bezpośrednio z bufora binarnego bez przekształcania. Protobuf zajmuje drugie miejsce, JSON — trzecie. XML to najwolniejszy format z popularnych.
Kotlinx Serialization to najlepszy wybór dla nowych projektów w Kotlin: generacja kompilatora, obsługa Kotlin Multiplatform, null safety. Moshi to dobry wybór dla projektów w Java, wydajniejszy niż Gson. Gson to najprostsza biblioteka na start, ale wolniejsza i używa refleksji.
Referencje cykliczne prowadzą do nieskończonej rekurencji przy serializacji. Rozwiązania: używaj referencji ID zamiast bezpośrednich referencji do obiektów, stosuj specjalne adaptery serializacji (np. @JsonIgnore w Jackson) lub przeprojektuj model danych, aby wyeliminować cykle.
Tak, szczególnie deserializacja danych z niepewnych źródeł. Podatności deserializacji mogą prowadzić do zdalnego wykonania kodu. Zalecenia: nie deserializuj danych z niezweryfikowanych źródeł, używaj allowlist klas przy deserializacji i waliduj schemat danych przed przetworzeniem.
Podsumowanie
Opracujemy aplikację mobilną pod klucz
IT Sectr tworzy aplikacje na iOS i Androida dla startupów i firm od 2017 roku. Doradzimy Ci i zaproponujemy najlepsze rozwiązanie.
Przeczytaj również