09/02/2026
El formato JSON (JavaScript Object Notation) se ha convertido en el estándar de facto para el intercambio de datos en la web moderna. Su simplicidad, legibilidad y eficiencia lo hacen indispensable en cualquier aplicación que interactúe con APIs, almacene configuraciones o transfiera información entre sistemas. Para los desarrolladores Java, la capacidad de leer y escribir datos JSON de manera fluida es una habilidad fundamental. Afortunadamente, Java cuenta con librerías robustas y fáciles de usar que simplifican enormemente estas operaciones, como Jackson y Gson. Este artículo explorará en profundidad cómo realizar operaciones de lectura y escritura de JSON en Java, utilizando estas dos poderosas herramientas. Desde la configuración inicial de tu proyecto hasta la manipulación avanzada de objetos y estructuras JSON, te guiaremos paso a paso para que domines este aspecto crucial del desarrollo Java.

Configuración del Entorno: Maven y Dependencias
Antes de sumergirnos en el código, es fundamental configurar nuestro entorno de desarrollo. Para proyectos Java, Maven es la herramienta de gestión de dependencias más utilizada. Necesitaremos añadir las dependencias de Jackson y Gson a nuestro archivo pom.xml.
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>org.example</groupId> <artifactId>JavaJSON</artifactId> <version>1.0-SNAPSHOT</version> <properties> <maven.compiler.source>11</maven.compiler.source> <maven.compiler.target>11</maven.compiler.target> </properties> <dependencies> <!-- Dependencia para Jackson --> <dependency> <groupId>com.fasterxml.jackson.core</groupId> <artifactId>jackson-databind</artifactId> <version>2.13.1</version> </dependency> <!-- Dependencia para Gson --> <dependency> <groupId>com.google.code.gson</groupId> <artifactId>gson</artifactId> <version>2.8.0</version> </dependency> </dependencies> </project>
Este bloque pom.xml define un proyecto Maven estándar. Las secciones <groupId>, <artifactId>, y <version> identifican tu proyecto. En <properties>, especificamos la versión del compilador de Java que utilizaremos (en este caso, Java 11). La clave está en la sección <dependencies>, donde declaramos las librerías externas que nuestro proyecto necesita. Hemos incluido jackson-databind (la parte principal de Jackson para mapeo de datos) y gson. Una vez que guardes este archivo, Maven descargará automáticamente estas librerías, haciéndolas disponibles para tu código.
Lectura y Escritura de JSON con Jackson
Jackson es una de las librerías más populares y potentes para trabajar con JSON en Java. Es la elección por defecto en muchos frameworks, incluyendo Spring Framework, debido a su rendimiento y flexibilidad. El corazón de Jackson para el mapeo de objetos es la clase ObjectMapper.
Para ilustrar cómo Jackson maneja la lectura y escritura de JSON, utilizaremos una clase Java simple que representará a una persona. Esta clase debe tener un constructor sin argumentos (constructor por defecto) y métodos getter y setter para sus propiedades, ya que Jackson los utiliza para serializar y deserializar los datos.
package com.arquitecturajava; public class Persona { private String nombre; private String apellidos; private int edad; public Persona(String nombre, String apellidos, int edad) { this.nombre = nombre; this.apellidos = apellidos; this.edad = edad; } public Persona() { // Constructor por defecto necesario para Jackson } public String getNombre() { return nombre; } public void setNombre(String nombre) { this.nombre = nombre; } public String getApellidos() { return apellidos; } public void setApellidos(String apellidos) { this.apellidos = apellidos; } public int getEdad() { return edad; } public void setEdad(int edad) { this.edad = edad; } }Esta clase Persona es un POJO (Plain Old Java Object) que Jackson puede mapear directamente. Ahora, veamos cómo leer un archivo JSON (por ejemplo, persona.json ubicado en la carpeta resources de tu proyecto) y convertirlo en un objeto Persona.
Primero, una utilidad para cargar el archivo desde resources:
private File getFileFromResource(String fichero) throws URISyntaxException { ClassLoader cargador = getClass().getClassLoader(); URL resource = cargador.getResource(fichero); if (resource == null) { throw new IllegalArgumentException("fichero no encontrado" + fichero); } else { return new File(resource.toURI()); } }Este método auxiliar getFileFromResource es útil para acceder a archivos que se encuentran dentro del classpath de tu aplicación, típicamente en la carpeta src/main/resources. Utiliza el ClassLoader para localizar el recurso por su nombre y lo convierte en un objeto File.
Ahora, la lógica principal para leer el JSON:
package com.arquitecturajava; import com.fasterxml.jackson.databind.ObjectMapper; import java.io.*; import java.net.URISyntaxException; import java.net.URL; public class LectorJSON { public static void main(String[] args) throws URISyntaxException { LectorJSON lector = new LectorJSON(); File fichero = lector.getFileFromResource("persona.json"); System.out.println("Leyendo archivo: " + fichero.getAbsolutePath()); ObjectMapper mapper = new ObjectMapper(); // Instancia de ObjectMapper try { // Lee el archivo JSON y lo mapea a un objeto Persona Persona persona = mapper.readValue(fichero, Persona.class); // Imprime los datos del objeto Persona System.out.println("Nombre: " + persona.getNombre()); System.out.println("Apellidos: " + persona.getApellidos()); System.out.println("Edad: " + persona.getEdad()); } catch (IOException e) { System.err.println("Error al leer el archivo JSON: " + e.getMessage()); e.printStackTrace(); } } private File getFileFromResource(String fichero) throws URISyntaxException { ClassLoader cargador = getClass().getClassLoader(); URL resource = cargador.getResource(fichero); if (resource == null) { throw new IllegalArgumentException("fichero no encontrado: " + fichero); } else { return new File(resource.toURI()); } } }En el método main, creamos una instancia de ObjectMapper. El método clave aquí es mapper.readValue(fichero, Persona.class). Este método toma el archivo JSON (o una cadena JSON, un InputStream, etc.) y la clase Java a la que queremos mapear los datos. Jackson se encarga automáticamente de hacer coincidir las claves del JSON con los nombres de las propiedades de la clase Persona, utilizando los setters para asignar los valores. Si el JSON contiene { "nombre": "Juan", "apellidos": "Pérez", "edad": 30 }, Jackson creará un objeto Persona con esos valores.

Ahora, para la escritura de JSON (también conocida como serialización), el proceso es igual de sencillo. Tomaremos un objeto Java y lo convertiremos en una cadena JSON o lo escribiremos directamente en un archivo.
package com.arquitecturajava; import com.fasterxml.jackson.databind.ObjectMapper; import java.io.File; import java.io.IOException; import java.net.URISyntaxException; public class EscritorJSON { public static void main(String[] args) throws URISyntaxException { ObjectMapper mapper = new ObjectMapper(); // Instancia de ObjectMapper Persona p = new Persona("Juan", "Gomez", 20); // Creamos un objeto Persona try { File fichero = new File("persona2.json"); // Definimos el archivo de salida // Si el archivo no existe, lo creamos. Esto es importante antes de escribir. if (fichero.createNewFile()) { System.out.println("Archivo 'persona2.json' creado."); } else { System.out.println("Archivo 'persona2.json' ya existe, sobrescribiendo."); } // Escribe el objeto Persona en el archivo JSON mapper.writeValue(fichero, p); System.out.println("Objeto Persona escrito en 'persona2.json' exitosamente."); // También podemos convertirlo a una cadena JSON directamente String jsonString = mapper.writeValueAsString(p); System.out.println("Objeto Persona como cadena JSON:\n" + jsonString); } catch (IOException e) { System.err.println("Error al escribir el archivo JSON: " + e.getMessage()); e.printStackTrace(); } } }En este ejemplo, creamos un objeto Persona manualmente. Luego, utilizando el método mapper.writeValue(fichero, p), Jackson toma el objeto p y lo convierte en una representación JSON, escribiéndola en el archivo persona2.json. De manera similar, mapper.writeValueAsString(p) nos permite obtener la representación JSON como una cadena de texto, útil para enviar datos a través de la red o para depuración. Jackson es excepcionalmente eficiente en estas tareas de serialización y deserialización, manejando estructuras complejas con facilidad.
Manipulación de JSON con Gson
Gson es otra popular librería de Java desarrollada por Google, también diseñada para convertir objetos Java a JSON y viceversa. Es conocida por su simplicidad y facilidad de uso, especialmente para casos donde la configuración es mínima.
¿Qué es Gson?
Gson es una API que facilita el mapeo entre objetos Java y sus representaciones JSON. Al igual que Jackson, permite la serialización (Java a JSON) y la deserialización (JSON a Java), pero también ofrece una API para trabajar directamente con la estructura JSON sin necesidad de definir clases Java preexistentes.
Estructura de JSON según Gson
Gson abstrae los elementos de un JSON en una jerarquía de clases que heredan de JsonElement. Entender esta estructura es clave para la manipulación manual de JSON:
JsonElement: La clase base para cualquier elemento JSON. Puede ser uno de los siguientes cuatro tipos.JsonObject: Representa un objeto JSON, es decir, un conjunto de pares clave-valor. Las claves son cadenas y los valores son otrosJsonElements. Se reconoce por las llaves{}.JsonArray: Representa un array JSON, que es una lista ordenada deJsonElements. Se reconoce por los corchetes[].JsonPrimitive: Representa un tipo de dato primitivo JSON (String, Number, Boolean) o tipos de objetos simples de Java comoInteger,Double,String, etc.JsonNull: Representa el valor nulo en JSON.
Serialización y Deserialización Automática con Gson
Gson facilita la conversión automática de objetos Java a JSON y viceversa. Para esto, simplemente necesitamos una instancia de la clase Gson y los métodos toJson() y fromJson().
Consideremos la clase FootballPlayer para un ejemplo:
import java.util.List; import java.util.ArrayList; // Necesario si se usa en el constructor por defecto o en algún setter public class FootballPlayer { private int dorsal; private String name; private List<String> demarcation; // Usamos List<String> para las demarcaciones private String team; public FootballPlayer(int dorsal, String name, List<String> demarcation, String team) { this.dorsal = dorsal; this.name = name; this.demarcation = demarcation; this.team = team; } public FootballPlayer() { // Constructor por defecto necesario para Gson } // Getters y Setters (omitidos para brevedad, pero necesarios para mapeo) public int getDorsal() { return dorsal; } public void setDorsal(int dorsal) { this.dorsal = dorsal; } public String getName() { return name; } public void setName(String name) { this.name = name; } public List<String> getDemarcation() { return demarcation; } public void setDemarcation(List<String> demarcation) { this.demarcation = demarcation; } public String getTeam() { return team; } public void setTeam(String team) { this.team = team; } @Override public String toString() { return "Dorsal=" + dorsal + ", Name=" + name + ", Demarcation=" + demarcation + ", Team=" + team; } }Serialización (Java a JSON):
import com.google.gson.Gson; import java.util.Arrays; import java.util.List; public class EscritorFutbolistas { public static void main(String[] args) { List<String> demarcacionesIniesta = Arrays.asList("Right winger", "Midfielder"); List<String> demarcacionesVilla = Arrays.asList("Centre forward"); List<FootballPlayer> spanishTeam = Arrays.asList( new FootballPlayer(6, "Iniesta", demarcacionesIniesta, "FC Barcelona"), new FootballPlayer(7, "Villa", demarcacionesVilla, "FC Barcelona") ); Gson gson = new Gson(); String json = gson.toJson(spanishTeam); // Convierte la lista de objetos a JSON System.out.println("Lista de futbolistas en JSON:\n" + json); // Ejemplo con un solo objeto String singlePlayerJson = gson.toJson(spanishTeam.get(0)); System.out.println("\nUn solo futbolista en JSON:\n" + singlePlayerJson); } }El método gson.toJson(objetoJava) es increíblemente potente. Toma cualquier objeto Java (o una colección de ellos) y lo transforma automáticamente en una cadena JSON bien formada, respetando la estructura de la clase y los tipos de datos.
Deserialización (JSON a Java):
import com.google.gson.Gson; import java.util.Arrays; // Necesario para Arrays.asList import java.util.List; public class LectorFutbolistas { public static void main(String[] args) { String jsonAll = "[{\"dorsal\":1,\"name\":\"Casillas\",\"demarcation\":[\"Goalkeeper\"],\"team\":\"Real Madrid\"}," + "{\"dorsal\":6,\"name\":\"Iniesta\",\"demarcation\":[\"Right winger\",\"Midfielder\"],\"team\&":\"FC Barcelona\"}," + "{\"dorsal\":7,\"name\":\"Villa\",\"demarcation\":[\"Centre forward\"],\"team\":\"FC Barcelona\"}]"; Gson gson = new Gson(); // Deserializa la cadena JSON a un array de FootballPlayer FootballPlayer[] footballPlayersArray = gson.fromJson(jsonAll, FootballPlayer[].class); System.out.println("Futbolistas deserializados (array):"); for (FootballPlayer player: footballPlayersArray) { System.out.println(player); } // También se puede deserializar a una List<FootballPlayer> usando Type // import java.lang.reflect.Type; // import com.google.gson.reflect.TypeToken; // Type listType = new TypeToken<List<FootballPlayer>>(){}.getType(); // List<FootballPlayer> footballPlayersList = gson.fromJson(jsonAll, listType); // System.out.println("\nFutbolistas deserializados (lista):"); // for (FootballPlayer player: footballPlayersList) { // System.out.println(player); // } // Deserializar un solo objeto String singlePlayerJson = "{\"dorsal\":10,\"name\":\"Messi\",\"demarcation\":[\"Forward\"],\"team\":\"PSG\"}"; FootballPlayer messi = gson.fromJson(singlePlayerJson, FootballPlayer.class); System.out.println("\nUn solo futbolista deserializado: " + messi); } }El método gson.fromJson(cadenaJson, Clase.class) es la contraparte del toJson(). Toma una cadena JSON y la clase Java de destino, realizando el mapeo automáticamente. Para colecciones (como una lista de futbolistas), es común deserializar primero a un array de la clase (FootballPlayer[].class) y luego, si es necesario, convertirlo a una List. La sección comentada muestra cómo deserializar directamente a una List utilizando TypeToken, lo cual es necesario para mantener la información de tipo genérico en tiempo de ejecución.

Deserialización Manual y Manipulación sin Beans Java
A veces, es posible que necesitemos leer una estructura JSON compleja o manipularla sin tener una clase Java predefinida para cada parte. Gson proporciona clases como JsonParser, JsonObject, JsonArray para este propósito.
Ejemplo de lectura manual de un JSON:
import com.google.gson.JsonArray; import com.google.gson.JsonElement; import com.google.gson.JsonObject; import com.google.gson.JsonParser; import java.util.ArrayList; import java.util.List; public class LectorManualJSON { public static void main(String[] args) { String jsonEquipo = "[{\"dorsal\":6,\"name\":\"Iniesta\",\"demarcation\":[\"Right winger\",\"Midfielder\"],\"team\":\"FC Barcelona\"}]"; JsonParser parser = new JsonParser(); // Parseamos la cadena JSON a un JsonElement, que en este caso es un JsonArray JsonArray gsonArr = parser.parse(jsonEquipo).getAsJsonArray(); System.out.println("Lectura manual de JSON:"); for (JsonElement obj: gsonArr) { // Cada elemento del array es un JsonObject JsonObject gsonObj = obj.getAsJsonObject(); // Obtenemos los elementos primitivos int dorsal = gsonObj.get("dorsal").getAsInt(); String name = gsonObj.get("name").getAsString(); String team = gsonObj.get("team").getAsString(); // Obtenemos el JsonArray para las demarcaciones JsonArray demarcationArray = gsonObj.get("demarcation").getAsJsonArray(); List<String> listDemarcation = new ArrayList<>(); for (JsonElement demarc: demarcationArray) { listDemarcation.add(demarc.getAsString()); } // Construimos el objeto FootballPlayer manualmente FootballPlayer jugador = new FootballPlayer(dorsal, name, listDemarcation, team); System.out.println(jugador); } } }Aquí, JsonParser.parse(jsonString) devuelve un JsonElement. Luego, usamos los métodos getAsJsonArray(), getAsJsonObject(), get("clave"), getAsString(), getAsInt() para navegar y extraer los datos de la estructura JSON de forma manual. Esto es útil cuando la estructura del JSON puede variar o cuando solo necesitamos acceder a partes específicas sin mapear todo.
Construir Cadena JSON sin Beans Java:
Gson también permite construir cadenas JSON programáticamente sin necesidad de tener clases Java que los representen.
import com.google.gson.Gson; import com.google.gson.JsonArray; import com.google.gson.JsonObject; import com.google.gson.JsonPrimitive; import java.util.Date; public class ConstructorJSONManual { public static void main(String[] args) { // Construir un JsonPrimitive JsonPrimitive primitivo = new JsonPrimitive(true); System.out.println("JsonPrimitive: " + primitivo.toString()); // true // Construir un JsonObject JsonObject objeto = new JsonObject(); objeto.addProperty("nombre", "Ana"); objeto.addProperty("edad", 25); objeto.addProperty("fechaRegistro", new Date().toString()); System.out.println("\nJsonObject: " + objeto.toString()); // {"nombre":"Ana","edad":25,"fechaRegistro":"..."} // Construir un JsonArray JsonArray array = new JsonArray(); array.add(new JsonPrimitive("Manzana")); array.add(new JsonPrimitive("Naranja")); array.add(objeto); // Se puede añadir otro JsonElement, como un JsonObject System.out.println("\nJsonArray: " + array.toString()); // ["Manzana","Naranja",{"nombre":"Ana","edad":25,...}] // Convertir a cadena JSON final Gson gson = new Gson(); System.out.println("\nJSON final usando Gson.toJson(): " + gson.toJson(array)); } }Utilizando JsonObject.addProperty("clave", valor) y JsonArray.add(JsonElement), podemos construir dinámicamente cualquier estructura JSON.
Manejo de Fechas con Gson:
Gson ofrece flexibilidad para el formato de fechas. Por defecto, serializa las java.util.Date como cadenas con un formato específico. Si necesitas un formato diferente, puedes configurar GsonBuilder.
import com.google.gson.Gson; import com.google.gson.GsonBuilder; import java.util.Date; public class FechasGson { public static void main(String[] args) { Date ahora = new Date(); // Gson por defecto Gson gsonDefault = new Gson(); String jsonDefaultDate = gsonDefault.toJson(ahora); System.out.println("Fecha por defecto (Gson): " + jsonDefaultDate); // "MMM dd, yyyy h:mm:ss a" // Gson con formato de fecha personalizado Gson gsonFormatted = new GsonBuilder().setDateFormat("dd/MM/yyyy HH:mm:ss").create(); String jsonFormattedDate = gsonFormatted.toJson(ahora); System.out.println("Fecha formateada (Gson): " + jsonFormattedDate); // "DD/MM/YYYY HH:MM:SS" // Deserializar una fecha con formato personalizado String fechaString = "\"26/02/2014 20:53:41\""; Date fechaDeserializada = gsonFormatted.fromJson(fechaString, Date.class); System.out.println("Fecha deserializada: " + fechaDeserializada); } }El GsonBuilder nos permite crear una instancia de Gson con configuraciones específicas, como setDateFormat(), lo que es crucial para asegurar la compatibilidad con diferentes formatos de fecha en los sistemas con los que interactuamos.
Jackson vs. Gson: ¿Cuál elegir?
Ambas librerías son excelentes opciones para trabajar con JSON en Java, pero tienen sus puntos fuertes:
| Característica | Jackson | Gson |
|---|---|---|
| Rendimiento | Generalmente superior en rendimiento y uso de memoria, especialmente para grandes volúmenes de datos. | Bueno, pero puede ser ligeramente más lento que Jackson en ciertos escenarios. |
| Flexibilidad y Características | Ofrece una API más rica y un control granular sobre la serialización/deserialización (anotaciones, módulos personalizados, etc.). Ampliamente utilizado en frameworks como Spring. | Más simple y fácil de empezar. Menos configuraciones por defecto, ideal para casos de uso sencillos o proyectos pequeños. |
| Manejo de Estructuras Complejas | Excelente. Su enfoque de "streaming" y su amplia gama de anotaciones permiten un control muy preciso. | Bueno, pero la manipulación de estructuras muy complejas o no mapeables a POJOs puede requerir más código manual. |
| Uso sin Beans Java | Aunque es posible, su API para manipulación directa de JSON es menos intuitiva que la de Gson. | Ofrece una API muy amigable (JsonParser, JsonObject, JsonArray) para construir y analizar JSON sin necesidad de clases Java. |
| Comunidad y Soporte | Amplia comunidad y muy activo, respaldado por su uso en Spring y otras tecnologías empresariales. | Gran comunidad, especialmente popular entre desarrolladores Android y para proyectos más sencillos. |
En resumen, si estás trabajando con Spring Boot o necesitas un control muy fino sobre el proceso de mapeo, Jackson es probablemente la mejor opción. Si buscas una solución más ligera, con una curva de aprendizaje más suave y una excelente API para la manipulación directa de estructuras JSON, Gson es una alternativa fantástica. A menudo, la elección dependerá de las necesidades específicas del proyecto y de las preferencias del equipo.

Preguntas Frecuentes
P: ¿Es necesario un constructor por defecto para las clases POJO al usar Jackson o Gson?
R: Sí, generalmente es necesario. Tanto Jackson como Gson utilizan el constructor por defecto (sin argumentos) para instanciar el objeto antes de usar los métodos setter para poblar sus propiedades. Si no se proporciona un constructor por defecto, ambas librerías pueden lanzar una excepción, aunque Jackson puede ser más tolerante si hay un constructor con argumentos que mapee directamente a los campos del JSON.
P: ¿Qué sucede si el JSON tiene campos que no existen en mi clase Java?
R: Por defecto, Jackson y Gson ignorarán los campos en el JSON que no tienen una propiedad correspondiente en tu clase Java. Esto es útil para la compatibilidad hacia adelante y atrás con APIs que pueden evolucionar.
P: ¿Cómo manejo campos nulos en JSON?
R: Si un campo en el JSON es nulo, Jackson y Gson lo mapearán a null en el objeto Java correspondiente. Si la propiedad en Java es un tipo primitivo (como int o boolean), y el JSON tiene un valor nulo para esa propiedad, se lanzará una excepción (por ejemplo, JsonMappingException en Jackson), ya que los tipos primitivos no pueden ser nulos. Para evitar esto, utiliza los tipos wrapper correspondientes (Integer, Boolean, etc.).
P: ¿Puedo personalizar el mapeo de nombres de campos (por ejemplo, de camelCase en Java a snake_case en JSON)?
R: Sí, ambas librerías permiten esto. Jackson usa anotaciones como @JsonProperty("nombre_json") en los campos o setters/getters de la clase Java. Gson utiliza la anotación @SerializedName("nombre_json"). Esto es muy común cuando se interactúa con APIs que siguen convenciones de nombres diferentes a las de Java.
P: ¿Cómo puedo manejar colecciones como Listas o Mapas en JSON?
R: Jackson y Gson manejan automáticamente la mayoría de las colecciones estándar de Java (List, Set, Map) siempre que los tipos genéricos estén correctamente definidos. Para deserializar tipos genéricos complejos (como List<MiClase>) con Gson, a menudo necesitarás usar TypeToken para proporcionar información de tipo en tiempo de ejecución, como se mostró brevemente en el ejemplo de deserialización de lista de FootballPlayer.
Conclusión
La lectura y escritura de JSON son operaciones fundamentales en el desarrollo moderno de aplicaciones Java. Tanto Jackson como Gson ofrecen soluciones robustas y eficientes para estas tareas, simplificando enormemente la interacción con datos estructurados. Jackson destaca por su rendimiento y extensibilidad, siendo la elección preferida en entornos empresariales y frameworks como Spring. Gson, por su parte, brilla por su sencillez y su API intuitiva para la manipulación directa de estructuras JSON, ideal para proyectos más pequeños o cuando se necesita agilidad. Dominar el uso de estas librerías te permitirá manejar el intercambio de datos de manera eficaz, haciendo tus aplicaciones Java más versátiles y potentes. Con los ejemplos y explicaciones proporcionadas, tienes una base sólida para empezar a integrar JSON en tus proyectos con confianza y eficiencia.
Si quieres conocer otros artículos parecidos a Dominando JSON en Java: Guía Completa de Lectura y Escritura puedes visitar la categoría Librerías.
