Сериализацията е процес на преобразуване на обект или структура от данни в последователен формат, подходящ за пренасяне по мрежа или запазване в файл. Обратният процес, десериализация, възстановява данните в первоначалното състояние. Според MDN Web Docs, сериализацията е необходима за всяка комуникация между процеси. Сериализацията е в основата на REST API, кеширането и обмена на данни между компонентите на приложението.
Основни моменти
Сериализация е процес на преобразуване на обект в оперативната памет в линейна последователност от байтове или знаци, която може да се пренесе по мрежа, да се запази в файл или да се предаде на друг процес. Без сериализация не е възможна мрежова комуникация, съхраняване на състояние и комуникация между процеси.
Сериализацията включва два противоположни процеса. Прекият процес (сериализация) опакова данните в формат за пренасяне. Обратният процес (десериализация) възстановява данните обратно в обект. Десериализацията е критична за сигурността: неправилни входни данни могат да доведат до уязвимости в приложението.
В разработката на мобилни приложения сериализацията се използва навсякъде: изпращане на заявки до сървъра и обработка на отговори, запазване на състоянието на приложението при завъртане на екрана, кеширане на данни на диска и пренасяне на данни между екраните чрез Intent (Android) или Segue (iOS).
Форматите за сериализация се разделят на текстови и бинарни. Текстовите формати (JSON, XML) са четими от човек и не изискват инструменти за преглед. Бинарните формати (Protobuf, FlatBuffers, MessagePack) са по-компактни и по-бързи, но не са четими без десериализация. Изборът на формат е компромис между производителност и удобство при дебагване.
Освен JSON, XML и Protobuf съществуват специализирани формати: FlatBuffers от Google за игри и AR, MessagePack — компактна бинарна алтернатива на JSON, Avro от Apache за големи данни в Kafka, YAML — конфигурационен формат с подкрепа за коментари.
| Формат | Тип | Схема | Размер | Скорост |
|---|---|---|---|---|
| JSON | Текстов | По избор | Среден | Средна |
| XML | Текстов | XSD | Голям | Ниска |
| Protobuf | Бинарен | Задължително | Малък | Висока |
| FlatBuffers | Бинарен | Задължително | Малък | Максимална |
| MessagePack | Бинарен | Не | Малък | Висока |
| Avro | Бинарен | JSON Schema | Малък | Висока |
Сериализация на мобилните платформи има своята специфика: ограничен трафик, по-слаби процесори и необходимост за запазване на състояние при завъртане на екрана. На Android се използват Gson, Moshi, Kotlinx Serialization. На iOS — Codable, JSONSerialization, PropertyListEncoder. Правилният избор на библиотека критично влияе на производителността на приложението.
Kotlinx Serialization — модерна библиотека от JetBrains за Kotlin Multiplatform Mobile. Подкрепя JSON, Protobuf, CBOR и потребителски формати. Генерирането на код става на етапа на компилация чрез плагина Kotlin Serialization, което осигурява висока производителност без използване на рефлексия.
Библиотеката Kotlinx Serialization използва анотация @Serializable за класове и компилаторен плагин за генериране на сериализатори. Това осигурява висока производителност и типова безопасност. По подразбиране форматът е JSON, но други формати също се подкрепят чрез допълнителни модули.
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)
// Сериализация
val jsonString = json.encodeToString(project)
// Десериализация
val restored = json.decodeFromString<Project>(jsonString)
}
Протоколът Codable — вграденият механизъм за сериализация в Swift. Той обединява протоколите Encodable (сериализация) и Decodable (десериализация). JSONEncoder и JSONDecoder автоматично обработват вложени структури, масиви, опционални стойности и потребителски ключове чрез 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)
Производителност на форматите за сериализация се оценява по три метрики: размер на съобщението, скорост на сериализация и скорост на десериализация. За мобилните приложения и трите са критични: размерът влияе на трафика и времето за зареждане, скоростта — на отзивчивостта на интерфейса и времето за стартиране на приложението.
Protobuf и FlatBuffers показват най-добри резултати благодарение на бинарното представяне. FlatBuffers се отличава по това, че не изисква отделна стъпка на десериализация — данните се четат директно от бинарния буфер, което е идеално за игри и AR приложения с изискване за минимално закъснение. JSON остава най-популярният формат за REST API, въпреки по-ниската производителност, благодарение на простотата и универсалността.
| Сценарий | Препоръчан формат | Причина |
|---|---|---|
| REST API | JSON | Универсалност, четимост, подкрепа |
| Микроуслуги | Protobuf | Компактност, скорост, gRPC |
| Игри / AR | FlatBuffers | Zero-copy, минимално закъснение |
| Big Data | Avro | Съвместимост с Kafka и Hadoop |
| Конфигурация | YAML | Коментари, четимост |
| Android layouts | XML | Платформен стандарт |
Практически тестове на набор от 1000 потребителски обекта показват: Protobuf създава съобщения с размер 12 KB (JSON — 85 KB, XML — 120 KB). Време за сериализация: Protobuf — 2 ms, JSON — 8 ms, XML — 25 ms. Тези цифри правят бинарните формати предпочитани за системи с високо натоварване и мобилни приложения с ограничен трафик.
Примерите демонстрират сериализацията на един и същ обект в различни формати. Това помага да се сравнят визуално размера и четимостта. Същият User обект ще бъде сериализиран в JSON, XML и Protobuf — ясно се вижда, че JSON е по-компактен от XML, а Protobuf е най-компактен и едновременно нечетим.
JSON — минималистичен синтаксис, ключове в кавички, стойности от различни типове. Заема 80 символа. Четимост висока, визуалната структура ясна. Подходящ за API, където скоростта на разработка и дебагване е важна.
XML — всяка елемент е овит в отварящ и затварящ етикет. Заема 150 символа. Четимост средна, структура строга. Подходящ за документооборот и системи, изискващи валидация чрез XSD.
Protobuf — бинарен, 32 байта за тези данни. Нечетим — изисква десериализация за преглед. Минималният размер го прави идеален за системи с високо натоварване и мобилни приложения.
{
"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>
Най-добрите практики помагат да се избегнат типичните грешки и да се избере правилната стратегия за сериализация за проекта. Спазването на тези препоръки подобрява производителността, сигурността и поддръжката на кода.
Сигурността на сериализацията е критично важен аспект, особено при десериализация на данни от ненадеждни източници. Атаките върху десериализацията могат да доведат до дистанционно изпълнение на код (RCE), което е една от най-опасните уязвимости в уеб и мобилните приложения. Най-известните случаи са свързани с Java Serializable и Python pickle.
Protobuf и JSON имат вградена защита срещу такива атаци, тъй като работят само с данни, а не с произволни обекти. Java Serializable, от друга страна, може да възстанови всяка клас, налична в classpath, което го прави опасен за приемане на данни от външни източници. На Android се препоръчва използването на Kotlinx Serialization или Moshi вместо стандартната Java Serialization.
Допълнителни мерки за сигурност: задайте лимит на размера на входните данни, валидирайте схемата преди десериализация, не се доверявайте на Content-Type от HTTP заглавията, използвайте бял списък (allowlist) за разрешените класове. Редовно актуализирайте библиотеките за сериализация, тъй като уязвимостите в тях се откриват и поправят периодично.
Често задавани въпроси
Сериализацията преобразува обект в последователност от байтове, маршалингът (marshalling) пренася данни между различни адресни пространства с запазване на типовете и структурата. Маршалингът включва сериализацията като част от процеса, но може също да включва кодиране на референции и управление на паметта.
FlatBuffers от Google осигурява максимална скорост благодарение на zero-copy десериализация — данните се четат директно от бинарния буфер без преобразуване. Protobuf е на второ място, JSON на трето. XML е най-бавният формат от разпространените.
Kotlinx Serialization е най-добрият избор за нови проекти в Kotlin: генериране от компилатора, подкрепа на Kotlin Multiplatform, null safety. Moshi е добрят избор за проекти на Java, по-производителен от Gson. Gson е най-простата библиотека за започване, но е по-бавна и използва рефлексия.
Цикличните референции водят до безкрайна рекурсия при сериализация. Решения: използвайте ID референции вместо преки референции към обекти, приложете специални адаптери за сериализация (напр. @JsonIgnore в Jackson) или препроектирайте модела на данни, за да премахнете циклите.
Да, особено десериализацията на данни от ненадеждни източници. Уязвимостите на десериализацията могат да доведат до дистанционно изпълнение на код. Препоръки: не десериализирайте данни от ненадеждни източници, използвайте бял списък от класове при десериализация и валидирайте схемата на данните преди обработката.
Обобщение
Ще разработим мобилно приложение под ключ
IT Sectr създава iOS и Android приложения за стартъпи и бизнеси от 2017 г. Ще ви консултираме и ще предложим най-доброто решение.
Прочетете също