Saltearse al contenido

Manipulación de JSON en Java

Manejo de tipos genéricos

El manejo de tipos genéricos es crucial cuando se trabaja con estructuras de datos complejas en JSON, especialmente al tratar con colecciones o clases parametrizadas. Gson proporciona herramientas para manejar estos casos de manera efectiva.

Importancia de los tipos genéricos

En Java, debido al borrado de tipos en tiempo de ejecución, Gson no puede determinar automáticamente el tipo exacto de los elementos en una colección genérica. Por ejemplo, List<String> y List<Integer> se ven iguales en tiempo de ejecución. Para manejar esto, Gson utiliza TypeToken.

Ejemplo con lista simple

Veamos cómo manejar una lista de strings:

1
import com.google.gson.Gson;
2
import com.google.gson.reflect.TypeToken;
3
import java.lang.reflect.Type;
4
import java.util.List;
5
import java.util.Arrays;
6
7
public class EjemploListaSimple {
8
public static void main(String[] args) {
9
Gson gson = new Gson();
10
11
// Creamos una lista de productos
12
List<String> productos = Arrays.asList("Laptop", "Smartphone", "Tablet");
13
14
// Convertimos la lista a JSON
15
String json = gson.toJson(productos);
16
System.out.println("JSON de productos: " + json);
17
18
// Ahora convertimos el JSON de vuelta a una List<String>
19
Type tipoListaString = new TypeToken<List<String>>(){}.getType();
20
List<String> productosRecuperados = gson.fromJson(json, tipoListaString);
21
22
System.out.println("Productos recuperados:");
23
for (String producto : productosRecuperados) {
24
System.out.println("- " + producto);
25
}
26
}
27
}

Este ejemplo muestra cómo serializar una lista de strings a JSON y luego deserializarla de vuelta a una lista de strings utilizando TypeToken.

Ejemplo con objetos anidados

Ahora, veamos un ejemplo más complejo con objetos anidados, como podría ser en un sistema de gestión de pedidos:

1
import com.google.gson.Gson;
2
import com.google.gson.reflect.TypeToken;
3
import java.lang.reflect.Type;
4
import java.util.List;
5
import java.util.Arrays;
6
7
class Producto {
8
String nombre;
9
double precio;
10
11
Producto(String nombre, double precio) {
12
this.nombre = nombre;
13
this.precio = precio;
14
}
15
}
16
17
class Pedido {
18
String numeroPedido;
19
List<Producto> productos;
20
21
Pedido(String numeroPedido, List<Producto> productos) {
22
this.numeroPedido = numeroPedido;
23
this.productos = productos;
24
}
25
}
26
27
public class EjemploObjetosAnidados {
28
public static void main(String[] args) {
29
Gson gson = new Gson();
30
31
// Creamos una lista de pedidos con productos
32
List<Pedido> pedidos = Arrays.asList(
33
new Pedido("001", Arrays.asList(
34
new Producto("Laptop", 999.99),
35
new Producto("Mouse", 19.99)
36
)),
37
new Pedido("002", Arrays.asList(
38
new Producto("Smartphone", 599.99),
39
new Producto("Cargador", 29.99)
40
))
41
);
42
43
// Convertimos la lista de pedidos a JSON
44
String json = gson.toJson(pedidos);
45
System.out.println("JSON de pedidos: " + json);
46
47
// Ahora convertimos el JSON de vuelta a una List<Pedido>
48
Type tipoPedidos = new TypeToken<List<Pedido>>(){}.getType();
49
List<Pedido> pedidosRecuperados = gson.fromJson(json, tipoPedidos);
50
51
// Mostramos los pedidos recuperados
52
System.out.println("\nPedidos recuperados:");
53
for (Pedido pedido : pedidosRecuperados) {
54
System.out.println("Número de pedido: " + pedido.numeroPedido);
55
for (Producto producto : pedido.productos) {
56
System.out.println(" - " + producto.nombre + ": $" + producto.precio);
57
}
58
System.out.println();
59
}
60
}
61
}

Este ejemplo ilustra cómo manejar una estructura más compleja: una lista de pedidos, donde cada pedido contiene una lista de productos. Aquí, TypeToken se utiliza para capturar la estructura completa de List<Pedido>, permitiendo a Gson deserializar correctamente la jerarquía completa de objetos.

Consideraciones importantes

  1. Uso de TypeToken: Siempre debemos usar clases anónimas para crear TypeTokens, no lambdas, ya que estas últimas no funcionan para capturar información de tipo genérico.

  2. Estructuras complejas: Cuanto más compleja sea la estructura de datos, más importante es el uso correcto de TypeToken para asegurar una deserialización precisa.

  3. Rendimiento: La creación de TypeTokens tiene un costo en rendimiento. En aplicaciones de alto rendimiento, debemos considerar estrategias para minimizar la creación repetida de TypeTokens.

  4. Wildcards: Hay que tener cuidado con los wildcards (?) en tipos genéricos. Gson puede tener dificultades para manejarlos correctamente en algunos casos.

El manejo adecuado de tipos genéricos con Gson te permite trabajar con estructuras de datos JSON complejas de manera segura y eficiente, manteniendo la integridad de los tipos en tu código Java.