Десеријализација је процес опоравке објекта из тока података JSON, XML или Protobuf, неопходан за сваку мобилну апликацију која ради са удаљеним API-јем. Према Apple Developer (2026), неправилно процесирање долазећих података остаје један од честих узрока падова на уређајима. JSONDecoder на iOS-у и Gson на Android-у су стандардни алати, али сваки има своје карактеристике и ограничења.
Главно
Десеријализација — процес претварања тока бајтова или структурираног текста у објекат језика програмирања. У мобилном развоју, овај процес се дешава сваки пут кад апликација прими одговор са сервера: JSON низ се претвара у инстанцу класе User, Order или Product. Од исправности десеријализације директно зависи стабилност екрана који приказују податке кориснику.
Серијализација и десеријализација су међусобно обрнути процеси, ретко симетрични у пракси. Серијализација претвара објекат у низ за слање на сервер, десеријализација опоравља објекат из примљеног низа. Сервер може послати поље које не постоји у моделу клијента, користити други формат датума или вратити null уместо броја. Према Square Engineering (2025), асиметрија формата је узрок 23% грешака мрежног слоја у Android апликацијама. За смањење ризика примењује се верзионисање шеме и строга уговорна спецификација кроз OpenAPI.
JSON остаје најпопуларнији формат за мобилне API-је због читљивости и уграђене подршке. Protobuf од Google-а користи се у системима високог оптерећења — 3-6 пута је компактнији од JSON-а и брже се парсира, али захтева генерацију кода из .датотека и није читљив без алата. XML се ређе среће у савременим мобилним апликацијама, али се користи у SOAP сервисима корпоративних система и Android конфигурационим датотекама. MessagePack — бинарни формат сличан JSON-у по структури, али компактнији, популаран у системима реалног времена.
Процес десеријализације пролази кроз три фазе. Прво, токенизација раздваја сирови текст на лексеме: кључеве, низове, бројеве и раздвајаче. Затим, синтаксна анализа проверава исправност структуре — да ли су заграде затворене, исправан ли је тип наводника, да ли формат одговара RFC 8259. Завршна фаза је мапирање на објекатни модел апликације, где се сваком JSON кључу додељује особина класе узимајући у обзир стратегију именовања.
У мобилном развоју обликовала су се два приступа мапирању. Reflection (Gson, JSONSerialization) анализира структуру класе у рантиму кроз Java Reflection API или Objective-C runtime — флексибилан је и не захтева додатну конфигурацију, али је спорији и троши више меморије. Code generation (Moshi codegen, kotlinx.serialization, Codable) генерише код у фази компилације: бржи је, сигурнији у погледу типова и не открива унутрашњу структуру кроз reflection. JetBrains и Square препоручују code generation за производне верзије — повећање перформанси достиже 2-4 пута у Google бенчмаркима.
struct User: Codable {
let id: Int
let name: String
let email: String
let createdAt: Date
}
let json = """
{
"id": 42,
"name": "Alice",
"email": "alice@example.com",
"created_at": "2026-06-01T12:00:00Z"
}
"""
let decoder = JSONDecoder()
decoder.keyDecodingStrategy = .convertFromSnakeCase
let user = try decoder.decode(User.self, from: data)
Примјер десеријализације JSON-а у User модел у Swift-у. Стратегија convertFromSnakeCase аутоматски претвара snake_case API кључеве у camelCase особине модела — стандардна пракса у iOS пројектима. Параметар data су сирови бајтови одговора сервера, добијени кроз URLSession. Руковање грешака кроз try омогућава хватање неисправног JSON-а без падања апликације.
JSONDecoder подржава четири стратегије кључева: useDefaultKeys (тачно подударање), convertFromSnakeCase (snake_case → camelCase), custom (closure) и convertFromKebabCase (kebab-case → camelCase). За датуме су предвиђени .iso8601, .secondsSince1970, .millisecondsSince1970 и прилагођени dateFormatter. Избор правилне стратегије је први корак ка стабилној десеријализацији, што спречава већину грешака неподударања формата.
JSONDecoder — стандардни механизам десеријализације у iOS SDK-у који ради са Codable протоколом. JSONDecoder аутоматски парсира JSON у инстанце struct или class, подржавајући угнијеждене објекте, низове и примитивне типове. За прилагођену логику користи се метода init(from: Decoder) — омогућава обраду нестандардних формата, изостављених поља у старијој верзији API-ја или спајање више JSON кључева у једну особину.
struct Order: Decodable {
let orderId: String
let amount: Double
let status: OrderStatus
enum OrderStatus: String, Decodable {
case pending, confirmed, shipped, cancelled
}
}
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .iso8601
let order = try decoder.decode(Order.self, from: jsonData)
DateDecodingStrategy одређује како JSONDecoder тумачи низове са датумима. Најчешће се користи .iso8601 — стандардни формат REST API-ја. Угнијеждени енум OrderStatus се аутоматски декодира из вредности JSON низова. Ово омогућава избегавање магичних бројева и чини код самодокументирајућим — статус порућбине увијек има строго дефинисан скуп вредности.
Почев од Swift 4.2, Codable подржава property wrappers за прилагођену десеријализацију појединачних особина. @DefaultValue — популаран wrapper, који поставља подразумевану вредност ако поље недостаје у JSON-у. @LosslessString претвара низ у број и обрнуто. Ово је посебно корисно кад сервер шаље id као низ „123”, а модел очекује Int. Property wrappers смањују шаблонски код у init(from:) и чине моделе чишћима.
На Android-у избор библиотеке за десеријализацију зависи од језика и потреба пројекта. Gson од Google-а — најзаступљенија опција, која ради кроз reflection, али има проблеме са перформансама на сложеним хијерархијама. Moshi од Square-а подржава и reflection и code generation, трошећи мање меморије и брже обрађујући велике одговоре. kotlinx.serialization од JetBrains-а — нативно Kotlin решење са интеграцијом у компилатор, које уопште не користи reflection.
@Serializable
data class User(
@SerialName("user_id")
val userId: Int,
val name: String,
val email: String,
@SerialName("created_at")
val createdAt: String
)
val json = Json { ignoreUnknownKeys = true }
val user = json.decodeFromString<User>(response)
@Serializable — Kotlin компилаторска анотација, која активира генерацију кода за класу. Параметар ignoreUnknownKeys спречава падове ако је сервер послао поље које не постоји у моделу. За мапирање snake_case кључева користи се @SerialName — еквивалент convertFromSnakeCase-а из iOS-а. Према JetBrains (2026), библиотека подржава вишеплатформеност: иста Serializable класа ради на Android-у, iOS-у (KMP) и серверском Kotlin-у.
Избор између библиотека своди се на компромис брзина-флексибилност. Gson је добар за прототипове и пројекте у Javi — не захтева анотације и ради „из кутије”. Moshi заузима средњу позицију: codegen кроз @JsonClass(generateAdapter = true) даје брзину блиску kotlinx.serialization-у, а reflection начин — флексибилност Gson-а. kotlinx.serialization — најбржа опција за чисте Kotlin пројекте, али захтева Kotlin 1.4+ и Kotlin Serialization прикључак у Gradle-у.
| Библиотека | Механизам | Брзина | KMP |
|---|---|---|---|
| Gson | Reflection | Ниска | Не |
| Moshi | Reflection / Codegen | Средња / Висока | Не |
| kotlinx.serialization | Compiler codegen | Висока | Да |
Type mismatch — ситуација када JSON садржи вредност једног типа, а модел очекује други. Сервер је послао низ „42” уместо броја или број 1 уместо boolean true. На iOS-у, JSONDecoder ће подразумевано бацити DecodingError.typeMismatch, на Android-у Gson ће покушати да конвертује, а Moshi и kotlinx.serialization захтевају експлицитне адаптере. Решење — користити lenient стратегије или прилагођене десеријализаторе за одређена поља.
Када сервер не укључује опционално поље, код пада са грешком. Optional у Swift-у и nullable типови у Kotlin-у решавају проблем: ако је поље null или недостаје у JSON-у, особина добија вредност nil/null, а апликација наставља рад. За обавезна поља, вреди проверити њихово постојање на нивоу API клијента пре десеријализације. Moshi и kotlinx.serialization подразумевано захтевају сва поља — nullable ознакавање и подразумеване вредности уклањају ово ограничење.
Промјена JSON структуре на серверу — чест извор падова у производњи. Стандардна пракса је верзионисање шеме кроз поље version у коренском објекту и подршка 2-3 претходне верзије на клијенту. kotlinx.serialization омогућава декларисање више модела за различите верзије и избор одговарајућег на основу поља version након првобитног парсирања у JsonElement. Додатна заштита — ignoreUnknownKeys за нова поља и подразумеване вредности за поља која могу бити уклоњена.
| Грешка | Симптом | Библиотека са заштитом |
|---|---|---|
| Type mismatch | DecodingError / изузетак | kotlinx — coerceInputValues = true |
| Недостаје поље | Пад при приступу | Moshi — @Transient + default |
| Неисправан формат датума | Грешка декодирања | JSONDecoder — dateDecodingStrategy |
| Додатна поља | Игноришу се или пад | kotlinx — ignoreUnknownKeys = true |
| Null у non-null пољу | Пад у рантиму | Moshi — lenient са @Nullable |
Логовање грешака десеријализације — обавезна пракса у производњи. Омотајте decode у do/catch, логујте сирови JSON и тип очекиваног модела у Crashlytics или Sentry. Ово ће вам омогућити да брзо одредите које поље којег API-ја се покварило и на којој верзији апликације. Без логовања, грешка десеријализације изгледа као мистериозан пад без контекста.
Често постављана питања
Парсирање — анализа структурираног текста на саставне елементе без обавезног креирања типизованог модела. Десеријализација је посебан случај парсирања, чији је резултат пуноправни објекат језика са познатим типовима особина. Парсирање може бити проточно, десеријализација увијек креира пун објекат.
За пројекат у чистом Kotlin-у препоручује се kotlinx.serialization — интегрисана је у компилатор, не користи reflection и подржава Kotlin Multiplatform. За постојећи пројекат у Javi — Moshi са code generation. Gson је боље оставити за легаси пројекте, где би његова замена захтевала значајна уложења.
На iOS-у користите keyDecodingStrategy = .convertFromSnakeCase у JSONDecoder-у. На Android-у у kotlinx.serialization користите @SerialName за свако поље. У Moshi-ју примењујте @Json(name=„field_name”) или глобални JsonAdapter.Factory. Јединствени стил на нивоу пројекта — best practice договорен у API уговору.
Најчешћи узрок је неочекивани null са сервера за поље које је објављено као обавезно. У развоју сервер враћа пуне податке, у производњи — скраћен одговор. Решење: означите сва потенцијално недостајућа поља као nullable (Kotlin) или optional (Swift), користите ignoreUnknownKeys и подразумеване вредности.
Code generation (Moshi codegen, kotlinx.serialization, Codable) ради 2-4 пута брже од reflection-а у Google бенчмаркима. Осим брзине, кодогенерација је сигурнија у погледу типова, не захтева метаподатке класа у рантиму, а грешке типова се откривају у фази компилације, а не у тренутку десеријализације.
Закључак
Развићемо мобилну апликацију под кључ
IT Sectr креира iOS и Android апликације за стартапе и предузећа од 2017. године. Саветоваћемо вас и предложити најбоље решење.
Прочитајте такође