3.4 JSON¶
JSON (JavaScript Object Notation) es un formato de texto para guardar e intercambiar datos. Es el formato más usado entre aplicaciones y servidores web, porque es compacto, fácil de leer para una persona y todos los lenguajes saben procesarlo.
{
"usuarios": [
{"id": 1, "nombre": "Juan", "edad": 30},
{"id": 2, "nombre": "Ana", "edad": 25}
]
}
Qué contiene un JSON¶
| En JSON | Ejemplo | En Kotlin es... |
|---|---|---|
Objeto { } |
{"id": 1} |
un mapa (o un objeto de una clase) |
Array [ ] |
[1, 2, 3] |
una lista |
| Texto | "Ana" |
una cadena |
| Número | 25 · 3.5 |
un entero o decimal |
| Booleano | true · false |
un booleano |
| Nulo | null |
el valor nulo |
Las reglas son estrictas: las claves y los textos van siempre entre comillas dobles, no se admite una coma al final de una lista ni de un objeto y no hay comentarios. La mayoría de errores con JSON son una de estas tres cosas.
Kotlin tampoco incluye un lector de JSON en la librería estándar. Este ejemplo usa Gson, que funciona igual que en Java y se añade con implementation("com.google.code.gson:gson:2.11.0"). La alternativa propia de Kotlin es kotlinx.serialization, que necesita su plugin de Gradle y la anotación @Serializable en las clases. Los nombres de los campos de la data class deben coincidir con las claves del JSON.
Leer, modificar y escribir¶
import com.google.gson.Gson
import com.google.gson.GsonBuilder
data class Usuario(var id: Int, var nombre: String, var edad: Int)
data class Datos(val usuarios: MutableList<Usuario>)
fun mostrar(datos: Datos) {
for (u in datos.usuarios) {
println("ID: ${u.id}, Nombre: ${u.nombre}, Edad: ${u.edad}")
}
}
fun main() {
val texto = """{"usuarios": [{"id": 1, "nombre": "Juan", "edad": 30}, {"id": 2, "nombre": "Ana", "edad": 25}]}"""
val datos = Gson().fromJson(texto, Datos::class.java)
mostrar(datos)
datos.usuarios[1].edad = 26 // actualizar
datos.usuarios.add(Usuario(3, "Eva", 22)) // insertar
datos.usuarios.removeIf { it.id == 1 } // eliminar
println("--- después de los cambios ---")
mostrar(datos)
println(GsonBuilder().setPrettyPrinting().create().toJson(datos))
}
Salida:
ID: 1, Nombre: Juan, Edad: 30
ID: 2, Nombre: Ana, Edad: 25
--- después de los cambios ---
ID: 2, Nombre: Ana, Edad: 26
ID: 3, Nombre: Eva, Edad: 22
{
"usuarios": [
{
"id": 2,
"nombre": "Ana",
"edad": 26
},
{
"id": 3,
"nombre": "Eva",
"edad": 22
}
]
}
El proceso siempre es el mismo en tres pasos:
- Convertir el texto en estructuras del lenguaje (mapas, listas u objetos).
- Trabajar con ellas como con cualquier mapa o lista. Con los datos convertidos a objetos, se trabaja como con cualquier lista de objetos:
usuarios[1].edad = 26,add(...)yremoveIf { ... }. - Convertirlas de nuevo en texto, con sangría si lo van a leer personas.
Trabajar con archivos y controlar los errores¶
Los datos suelen estar en un archivo. Al leerlo pueden pasar dos cosas que hay que controlar siempre: que el archivo no exista o que su contenido no sea un JSON válido. Un JSON mal formado lanza una JsonSyntaxException (en Gson).
import com.google.gson.Gson
import com.google.gson.JsonSyntaxException
import java.io.File
fun cargar(ruta: String): List<*>? {
val archivo = File(ruta)
if (!archivo.exists()) {
println("No existe el archivo '$ruta'")
return null
}
return try {
val datos = Gson().fromJson(archivo.readText(), Map::class.java)
datos["usuarios"] as List<*>
} catch (e: JsonSyntaxException) {
println("El archivo '$ruta' no contiene un JSON válido")
null
}
}
fun main() {
cargar("no_existe.json")
File("malo.json").writeText("{ esto no es json")
cargar("malo.json")
File("bueno.json").writeText(
"""{"usuarios": [{"id": 1, "nombre": "Juan", "edad": 30}, {"id": 2, "nombre": "Ana", "edad": 25}]}"""
)
val usuarios = cargar("bueno.json")
println("Cargados ${usuarios?.size} usuarios")
File("malo.json").delete()
File("bueno.json").delete()
}
Salida:
No existe el archivo 'no_existe.json'
El archivo 'malo.json' no contiene un JSON válido
Cargados 2 usuarios
Comprobar la existencia antes de abrir y capturar el error de formato permite dar un mensaje claro en vez de que el programa se detenga. Los archivos de texto se guardan en UTF-8, la codificación habitual del JSON.
Errores frecuentes¶
| Error | Cómo evitarlo |
|---|---|
| Comillas simples en el texto del JSON | En JSON solo valen las dobles |
| Una coma de más al final | Quítala: JSON no la permite |
| Esperar un número y recibir texto (o al revés) | Comprueba el tipo o convierte |
| Pedir una clave que no existe | Comprueba con las consultas seguras del apartado 3.2 |
| Perder las tildes al guardar | Usa UTF-8 en lectura y escritura |
Para practicar¶
Haz el ejercicio 3.4 de JSON, la gestión de usuarios en un archivo.