JSON (JavaScript Object Notation) es un formato de intercambio de información que está basado en estructuras de pares clave-valor. Es un formato mucho más ligero que XML y más indicado que éste en determinados escenarios.
Puede darse la situación de que en nuestra aplicación Java, necesitemos atender peticiones representadas en JSON, transformarlas a Java, tratar los datos y devolver una respuesta en JSON. Para resolver este problema podemos implementar «a mano» la lógica de negocio para serializar y deserializar nuestro JSON, lo que supondrá un esfuerzo considerable.
Sin embargo, existen múltiples librerías para poder manipular contenido en JSON con Java, facilitando enormemente esta tarea. Ya hemos visto cómo podemos crear objeto JSON con GSON. También, alguno dirá: «Pues yo uso Spring MVC o Jersey y lo hacen automáticamente».
Trabajando con JSON en Java: La librería Gson
En este tutorial os hemos presentado la librería Gson, una librería excelente para trabajar con objetos JSON y Java.
Instanciación de Gson
El uso de esta librería se basa en el uso de una instancia de la clase Gson. Dicha instancia se puede crear de manera directa (new Gson()) para transformaciones sencillas o de forma más compleja con GsonBuilder para añadir distintos comportamientos.
Lea también: IVA 21% Excel
Deserialización con Gson
Deserializar a java.util.Properties
En este primer ejemplo (test) vamos a ver cómo deserializar nuestro objeto JSON en un objeto Properties (Java). Deserializar este objeto en un Properties (java.util.Properties) es muy sencillo con Gson.
Basta con crear un objeto Gson e invocar a su método fromJson. Como parámetros le pasaremos el objeto JSON como String y la clase del objeto en que se deserializará.
Deserializar a un objeto propio
En este ejemplo vamos a hacer lo mismo que en el anterior pero deserializando el objeto JSON en un objeto propio. Vemos que los atributos de nuestra clase: id, nombre y empresa, coinciden con las claves del objeto JSON. En posteriores ejemplos veremos que esto no tiene por qué ser necesariamente así.
Deserializar a una lista de objetos propios
Este ejemplo es parecido al segundo pero con la salvedad de que ahora no convertimos un objeto JSON en un objeto Java propio, sino en una lista de éstos. Como vemos hay dos empleados en el array.
Para que Gson comprenda que tiene que deserializar el objeto JSON en una lista de objetos propios hacemos lo mismo que en los ejemplos anteriores. La única diferencia es que ahora el segundo parámetro del método fromJSON no es la clase a la que queremos deserializar el objeto JSON sino un objeto Type (java.lang.reflect.Type) que habremos creado mediante TypeToken.
Lea también: Guía IVA reducido
Deserializar a clases genéricas
Como hemos visto en el ejemplo anterior Gson es capaz de deserializar un objeto JSON en una lista tipada. Por supuesto esto es extensible a cualquier otra clase genérica. Veamos un ejemplo.
Para deserializar un objeto JSON en una de estas clases con tipo genérico, lo hacemos de la misma forma que en el ejemplo anterior. Vamos a hacer una especie de «mix» entre el ejemplo 4 y el 5. ¿Y qué hay que hacer para mapear la lista de «SolicitudVacaciones»? Pues absolutamente nada fuera de lo que hemos visto.
Manejo de fechas
En este ejemplo vamos a ver cómo transformar fechas de nuestro objeto JSON en fechas de nuestro objeto Java (java.util.Date). Nuestro objeto JSON representa un intervalo de fechas (lo usaremos para simular una solicitud de vacaciones).
Para transformar las fechas lo haremos de la misma forma que en los ejemplos anteriores pero, al instanciar nuestro objeto Gson, lo haremos con GsonBuilder. Inicializamos el formato de fecha con el método setDateFormat (en nuestro caso dd/MM/yyyy) y creamos la instancia con el método create.
Mapeo de propiedades con nombres diferentes
Como vimos en el ejemplo 2, si realizamos la deserialización del objeto JSON al objeto Java directamente con «fromJson», ésta se realizará propiedad a propiedad entre el objeto JSON y el Java de manera automática si las propiedades y atributos tienen el mismo nombre.
Lea también: ¿Cómo localizar tus XML del SAT?
Sin embargo, podemos hacer que esto no sea así. La nueva propiedad «d» simboliza el número de días del intervalo de tiempo. Imaginemos que queremos mapearlo en un nuevo atributo «totalDias» en nuestra clase SolicitudVacaciones por temas de claridad de código.
Lectura desde un fichero
Nuestro objeto Gson no solo acepta un String como representación JSON del objeto a deserializar. También puede leerlo desde un fichero y realizar la misma tarea. Imaginemos que tenemos un fichero json.txt con el objeto JSON del ejemplo anterior.
Serialización con Gson
Serialización básica de un objeto
Ahora vamos a ver el ejemplo contrario al anterior. Partiendo de nuestro objeto empleado, queremos obtener su representación JSON. Para ello, igual que en los dos ejemplos anteriores, creamos una instancia de Gson.
Serialización con formato legible
Si nos fijamos bien en el ejemplo anterior, la representación JSON de nuestro «Empleado» viene bastante comprimida. Todo en una línea y sin espacios o tabulaciones.
Es posible que en algunos casos queramos mostrar la representación JSON de una forma más clara, por ejemplo en un fichero de log. Gson nos permite crear representaciones JSON un poco más vistosas. Para ello debemos crear una instancia de Gson con GsonBuilder.
Resumen de métodos comunes de Gson
| Método/Característica de Gson | Descripción | Caso de Uso Principal |
|---|---|---|
| new Gson() | Crea una instancia básica de Gson. | Transformaciones sencillas, serialización/deserialización directa. |
| GsonBuilder().create() | Crea una instancia de Gson con configuraciones personalizadas. | Formato legible, manejo de fechas, adaptadores personalizados. |
| fromJson(String json, Class<T> classOfT) | Deserializa una cadena JSON a un objeto de la clase especificada. | Deserializar JSON a un objeto Java (ej. Properties, objeto propio). |
| fromJson(String json, Type typeOfT) | Deserializa una cadena JSON a un tipo genérico o complejo. | Deserializar JSON a listas de objetos (ej. List<Empleado>) o tipos genéricos. |
| toJson(Object src) | Serializa un objeto Java a su representación JSON compacta. | Convertir un objeto Java a una cadena JSON. |
| GsonBuilder().setPrettyPrinting().create() | Crea una instancia de Gson que produce JSON formateado con indentación y saltos de línea. | Generar JSON para logs, depuración o una presentación más legible. |
| GsonBuilder().setDateFormat("formato").create() | Crea una instancia de Gson con un formato de fecha específico para serialización/deserialización. | Manejo de fechas con patrones personalizados (ej. "dd/MM/yyyy"). |
| @SerializedName("nombre_json") | Anotación para mapear un campo Java a un nombre de campo JSON diferente. | Cuando los nombres de los atributos de la clase no coinciden con las claves del JSON. |
| fromJson(Reader reader, Class<T> classOfT) | Deserializa un JSON leído desde un objeto Reader (como un fichero o un InputStream). | Leer objetos JSON directamente desde un archivo. |
Alternativas a Gson: La librería JSON-Simple
Aunque Gson es muy potente, existen otras alternativas. En este caso vamos a crear objeto JSON con JSON-Simple mediante código Java.
JSON-Simple es una librería ligera que nos permite serializar y deserializar contenido en JSON. Lo primero de todo será importar la librería JSON-Simple.
Ahora que ya tenemos el objeto lo que haremos será utilizar el método .put() para ir añadiendo propiedades al objeto JSON. Podemos volcar por consola el contenido de nuestro objeto JSON en formato cadena mediante el método .toString() que también nos ofrece la clase JsonObject.
Consideraciones y solución de problemas
Visibilidad de campos y clases record
Entiendo que estás teniendo dificultades al intentar crear un archivo JSON que almacene una lista con resultados utilizando el método de transformación de JSON a clase a través de anotaciones.
Una posible solución a este problema es asegurarte de que los campos de la clase tengan la visibilidad adecuada para que la librería Gson pueda acceder a ellos al momento de transformar el JSON a la clase.
Si esto no resuelve tu problema, también puedes considerar la opción de utilizar el segundo método de transformación de JSON a clase, a través de una clase record, como lo mencionaste. Espero que estas sugerencias te sean de ayuda para resolver el problema que estás enfrentando al crear el archivo JSON.
