Moshi é uma biblioteca JSON moderna da Square, criada especificamente para Kotlin e Android levando em conta as limitações do Gson. Ela é totalmente compatível com a segurança nula do Kotlin, gera código em tempo de compilação e não usa reflexão, o que melhora o desempenho e a confiabilidade. De acordo com Square Moshi, 2024, Moshi fornece serialização previsível e suporta adaptadores personalizados para qualquer tipo de dados.
Pontos principais
Moshi é uma biblioteca JSON para JVM, Android e Kotlin Multiplatform, criada pela Square (os autores do OkHttp e Retrofit). Ao contrário do Gson, Moshi não depende de reflexão — os adaptadores são gerados em tempo de compilação através da anotação @JsonClass(generateAdapter = true). Isso torna Moshi mais rápida, segura e previsível ao trabalhar com construções específicas do Kotlin.
A principal diferença do Moshi em relação aos seus antecessores é a rejeição da reflexão. A reflexão permite que o Gson trabalhe com qualquer classe sem preparação, mas o custo é uma inicialização lenta, a impossibilidade de otimização pelo compilador e o risco de erros em tempo de execução. Moshi exige declaração explícita de classes para geração de código, mas em troca oferece a velocidade do código escrito à mão e segurança total de tipos em tempo de compilação.
// Adicionar Moshi ao build.gradle
dependencies {
implementation "com.squareup.moshi:moshi:1.15.0"
implementation "com.squareup.moshi:moshi-kotlin:1.15.0"
kapt "com.squareup.moshi:moshi-kotlin-codegen:1.15.0"
}
// Modelo simples com geração de código
@JsonClass(generateAdapter = true)
data class User(
@Json(name = "user_id")
val id: Int,
val name: String,
val email: String,
val avatar: String? = null
)
// Uso
val moshi = Moshi.Builder()
.build()
val jsonAdapter = moshi.adapter(User::class.java)
Para começar a trabalhar com Moshi, é necessário adicionar dependências ao build.gradle e anotar os modelos. Moshi.Builder serve como ponto de entrada: através dele são adicionados adaptadores integrados para tipos padrão, adaptadores personalizados e configurado o comportamento da biblioteca. Moshi suporta adaptadores para Date, Enum, Collection e Map nativamente, mas as classes Kotlin exigem o módulo moshi-kotlin. Ao contrário do Gson, Moshi não usa reflexão para classes Kotlin por padrão — para isso, o KotlinJsonAdapterFactory é conectado, servindo como alternativa quando a geração de código não é usada ou a classe não está anotada com @JsonClass. Essa abordagem garante que o desenvolvedor escolha explicitamente entre o desempenho da geração de código e a flexibilidade da reflexão para cada classe específica.
Após construir Moshi através do Builder, o desenvolvedor obtém uma instância de Moshi e solicita um adaptador para a classe desejada. JsonAdapter é o objeto central que realiza a serialização via toJson() e a desserialização via fromJson(). Moshi usa automaticamente o adaptador gerado se a classe estiver anotada com @JsonClass(generateAdapter = true), caso contrário aplica o KotlinJsonAdapterFactory reflexivo como alternativa. Essa abordagem combina a velocidade da geração de código com a flexibilidade de um mecanismo reflexivo para projetos de qualquer escala e complexidade. Moshi é adequada tanto para aplicações pequenas quanto para grandes projetos empresariais com centenas de modelos de dados.
// Configurar Moshi com KotlinJsonAdapterFactory
val moshi = Moshi.Builder()
.add(KotlinJsonAdapterFactory())
.add(LocalDateAdapter())
.build()
// Usar o adaptador
val adapter = moshi.adapter(User::class.java)
// Serialização
val user = User(1, "Alice", "alice@test.com")
val json = adapter.toJson(user)
// Desserialização
val jsonString = """{"user_id":2,"name":"Bob","email":"bob@test.com"}"""
val parsedUser = adapter.fromJson(jsonString)
// Trabalhar com listas
val listAdapter = moshi.adapter(
Types.newParameterizedType(
List::class.java,
User::class.java
)
)
Moshi usa anotações para configurar a serialização e suportar tipos personalizados. @Json(name = "...") define a chave JSON para um campo. @Transient exclui um campo da serialização. @JsonClass(generateAdapter = true) ativa a geração de código. Para lógica personalizada, Moshi fornece as anotações @ToJson e @FromJson, que podem ser colocadas em uma classe adaptadora separada.
A anotação @Json substitui o @SerializedName do Gson e funciona de forma semelhante: o campo kotlinName é associado à chave JSON "kotlin_name". Para tipos que Moshi não consegue serializar por padrão (por exemplo, LocalDate), o desenvolvedor cria uma classe com métodos @ToJson e @FromJson. Os adaptadores são registrados via Moshi.Builder.add() e aplicados globalmente ou a um tipo específico. Moshi suporta classes seladas e serialização polimórfica via @JsonClass com um discriminador explícito, permitindo trabalhar com hierarquias de tipos em JSON sem verificação manual de campos. Durante a desserialização, Moshi ignora chaves JSON desconhecidas por padrão, garantindo compatibilidade reversa ao adicionar novos campos no servidor sem alterar o código do cliente. Para depuração, o modo estrito pode ser ativado via failOnUnknown, que lança uma exceção quando chaves desconhecidas são encontradas.
// Adaptador personalizado para LocalDate
class LocalDateAdapter {
@ToJson
fun toJson(date: LocalDate): String {
return date.format(DateTimeFormatter.ISO_LOCAL_DATE)
}
@FromJson
fun fromJson(dateString: String): LocalDate {
return LocalDate.parse(dateString)
}
}
// Modelo com anotações Moshi
@JsonClass(generateAdapter = true)
data class Event(
@Json(name = "event_id")
val id: Int,
@Json(name = "event_date")
val date: LocalDate,
@Transient
val localCache: String? = null
)
// Registrar o adaptador
val moshi = Moshi.Builder()
.add(LocalDateAdapter())
.add(KotlinJsonAdapterFactory())
.build()
Comparar Moshi e Gson é uma pergunta comum ao escolher uma biblioteca JSON para um projeto Android. Moshi vence no desenvolvimento moderno com Kotlin graças à geração de código, segurança nula e velocidade. Gson continua relevante para projetos Java, código legado e cenários onde a configuração mínima é importante. A diferença torna-se perceptível com grandes volumes de dados e modelos complexos.
Testes de desempenho mostram que Moshi com geração de código é 2–5 vezes mais rápido que Gson em operações de serialização e desserialização. A principal vantagem do Moshi é o tratamento correto da segurança nula do Kotlin: se um campo estiver ausente no JSON e o modelo o declarar como non-null sem valor padrão, Moshi lança uma exceção no momento da desserialização, prevenindo erros ocultos.
| Característica | Gson | Moshi |
|---|---|---|
| Mecanismo | reflexão | geração de código / reflexão |
| Segurança nula | não considera | suporte completo ao Kotlin |
| Velocidade | média | alta |
| Valores padrão | não suporta | suporta |
| Kotlin Multiplatform | não | sim |
| Tamanho da biblioteca | ~240 Kb | ~150 Kb |
A escolha entre Moshi e Gson depende do contexto do projeto. Novos projetos em Kotlin se beneficiam do Moshi graças à segurança de tipos e desempenho. Gson continua sendo uma escolha razoável para suportar código Java, estruturas JSON dinâmicas ou quando a simplicidade de configuração é mais importante que a velocidade. Para Kotlin Multiplatform, Moshi é a única das duas opções que suporta esta plataforma.
Ao migrar de Gson para Moshi, as principais mudanças dizem respeito a anotações e adaptadores. O @SerializedName do Gson é substituído por @Json(name = "..."), e os JsonSerializer/JsonDeserializer personalizados pelo par @ToJson/@FromJson. Para modelos com valores padrão e campos anuláveis, Moshi se comporta de forma mais previsível: se um campo non-null sem padrão estiver ausente no JSON, Moshi lança JsonDataException, prevenindo NPEs ocultos. A integração com Retrofit via MoshiConverterFactory é adicionada com uma única dependência e não requer alteração na arquitetura da camada de rede. Para ofuscação via ProGuard ou R8, é necessário adicionar regras para preservar classes anotadas com @JsonClass e adaptadores gerados, caso contrário a serialização quebrará na compilação de release. No geral, a migração de Gson para Moshi é justificada em novos projetos Kotlin onde desempenho e segurança de tipos são importantes.
// Comparação de serialização: Gson vs Moshi
data class Sample(
val name: String,
val count: Int,
val tags: List<String> = listOf()
)
// Gson: funciona através de reflexão
val gson = Gson()
val fromGson = gson.fromJson("""{"name":"test"}""",
Sample::class.java)
// count = 0 (padrão), mas segurança nula não é verificada
// Moshi: requer um adaptador, segurança nula é explícita
@JsonClass(generateAdapter = true)
data class SampleMoshi(
val name: String,
val count: Int,
val tags: List<String> = listOf()
)
Perguntas frequentes
Moshi é uma biblioteca JSON da Square para Kotlin e Android que usa geração de código em vez de reflexão. Ela fornece alto desempenho, tratamento correto da segurança nula do Kotlin e compatibilidade com Kotlin Multiplatform.
Moshi supera Gson em velocidade (2–5 vezes mais rápido graças à geração de código), segurança (respeita anotações nulas do Kotlin) e tamanho (~90 Kb menor). Moshi também suporta Kotlin Multiplatform e valores padrão em data class.
@JsonClass(generateAdapter = true) instrui Moshi a gerar um adaptador para a classe dada em tempo de compilação. O adaptador gerado realiza a serialização diretamente, sem reflexão, proporcionando máximo desempenho.
Crie uma classe com métodos anotados com @ToJson (serialização) e @FromJson (desserialização). Registre a instância via Moshi.Builder.add(). Moshi encontrará e aplicará automaticamente o adaptador ao trabalhar com o tipo correspondente.
Sim, Moshi suporta Kotlin Multiplatform a partir da versão 1.13.0. Isso faz dele a única solução JSON popular para projetos KMP, permitindo usar código de serialização comum em todas as plataformas alvo.
Resumo
Vamos desenvolver um aplicativo móvel chave na mão
A IT Sectr cria aplicativos para iOS e Android para startups e empresas desde 2017. Nós vamos aconselhá-lo e propor a melhor solução.
Leia também