Convertir objeto Java (POJO) hacia y desde JSON con Gson

En este tutorial, veremos ejemplos sobre cómo convertir Java Object (POJO) a JSON y cómo convertir JSON a Java Object usando Gson.

Introducción

El formato JSON es una de las formas más populares de serializar datos. Saber leerlo y escribirlo es una habilidad importante para cualquier programador. Hay un par de bibliotecas de Java que pueden analizar JSON, pero en este tutorial nos centraremos en un proyecto de código abierto desarrollado por Google llamado GSON.

GSON es una biblioteca Java liviana que proporciona funcionalidad de serialización/deserialización. Lo que hace que GSON se destaque es su soporte para Tipos genéricos, que está limitado con algunas bibliotecas alternativas, pero no con todas.

Note: If you're not familiar with Generics and why this is a big deal - feel free to read our Guía para comprender los genéricos de Java.

Como estamos trabajando con una biblioteca externa, agreguemos la dependencia. Si está utilizando Maven, puede agregarlo con:

1
2
3
4
5
<dependency>
    <groupId>com.google.code.gson</groupId>
    <artifactId>gson</artifactId>
    <version>${version}</version>
</dependency>

O si está usando Gradle, puede agregar:

1
compile group: 'com.google.code.gson', name: 'gson', version: ${version}

Creación de una clase personalizada

Vamos a crear una clase personalizada que primero serializaremos en JSON, y en la que deserializaremos desde JSON - Student:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
public class Student {
    private String firstName;
    private String lastName;
    private int studentID;
    private String email;
    private List<String> courses;
    private FINANCE_TYPE financeType;

    // Getters, setters, constructor, toString()
}

Para nuestro Estudiante, también tenemos una enumeración que representa si están dentro del presupuesto (SUBSIDIADO) o no (SIN SUBSIDIO):

1
2
3
public enum FINANCE_TYPE {
    SUBSIDIZED, UNSUBSIDIZED
}

Convertir objeto Java en objeto JSON con GSON

Ahora que hemos definido nuestra clase, hagamos una instancia de ella y serialicémosla en su representación JSON equivalente. Haremos esto usando el método llamado toJson() que toma un objeto como argumento y devuelve la representación JSON de ese objeto:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
// Defining courses
List<String> physicsCourses = Arrays.asList("Physics 8.01", "Physics 8.012");
List<String> musicCourses = Arrays.asList("Jazz", "Blues");
 
// Instantiating students
Student max = new Student("Max", "Tegmark", 1254, "[correo electrónico protegido]", physicsCourses, FINANCE_TYPE.SUBSIDIZED);
Student amy = new Student("Amy", "Winehouse", 1328, "[correo electrónico protegido]", musicCourses, FINANCE_TYPE.SUBSIDIZED);

// Instantiating Gson
Gson gson = new Gson();

// Converting POJO to JSON
String maxJson = gson.toJson(max);
String amyJson = gson.toJson(amy);

System.out.println(maxJson);
System.out.println(amyJson);

Esto convierte nuestros POJO en cadenas JSON, que cuando se imprimen dan como resultado:

1
2
{"firstName":"Max","lastName":"Tegmark","studentID":1254,"email":"[correo electrónico protegido]","courses":["Physics 8.01","Physics 8.012"],"financeType":"SUBSIDIZED"}
{"firstName":"Amy","lastName":"Winehouse","studentID":1328,"email":"[correo electrónico protegido]","courses":["Jazz","Blues"],"financeType":"SUBSIDIZED"}

Convertir cadena JSON en objeto Java

Para revertir este proceso y asignar un objeto JSON a un POJO, utilizaremos el método fromJson(). Acepta una cadena JSON o un Lector y una clase o un TypeToken.

Primero echemos un vistazo al primero:

1
2
3
4
5
6
String maxJson = "{\"firstName\":\"Max\",\"lastName\":\"Tegmark\",\"studentID\":1254,\"email\":\"[correo electrónico protegido]\",\"courses\":[\"Physics 8.01\",\"Physics 8.012\"],\"financeType\":\"SUBSIDIZED\"}";

Gson gson = new Gson();
Student max = gson.fromJson(maxJson, Student.class);

System.out.println(max);

Esto crea una instancia y rellena el objeto max con los datos del objeto JSON:

1
Student{firstName='Max', lastName='Tegmark', studentID=1254, email='[correo electrónico protegido]', courses=[Physics 8.01, Physics 8.012], financeType=SUBSIDIZED}

Convertir archivo JSON en objeto Java

Ahora, es posible que no estemos trabajando con JSON en formato de cadena; a menudo tenemos que leer archivos JSON. El método fromJson() acepta una instancia Reader, que también podemos usar para proporcionar datos JSON.

Vamos a mover los datos de Amy a un archivo amy.json:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
{
  "firstName":"Amy",
  "lastName":"Winehouse",
  "studentID":1328,
  "email":"[correo electrónico protegido]",
  "courses":[
    "Jazz",
    "Blues"
  ],
  "financeType":"SUBSIDIZED"
}

Ahora, podemos usar un Reader, como FileReader para leer este archivo y usarlo para la entrada en lugar de una Cadena. Además, en lugar de usar Student.class, proporcionamos un Type. Este ‘Tipo’ se extrae del ‘TypeToken’ de Gson, que es muy similar al ‘TypeReference’ de Jackson:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
// Instantiate FileReader for amy.json
Reader input = new FileReader("./src/main/resources/amy.json");
//Instantiate Gson
Gson gson = new Gson();
// Create a Type via TypeToken for the Student class
Type type = new TypeToken<Student>(){}.getType();
// Read the `input` and cast into `type`
Student amy = gson.fromJson(input, type);
// Print result
System.out.println(amy);

Esto, seguramente, también instancia y llena nuestro POJO ‘Estudiante’:

1
Student{firstName='Amy', lastName='Winehouse', studentID=1328, email='[correo electrónico protegido]', courses=[Jazz, Blues], financeType=SUBSIDIZED}

Impresión compacta y bonita

Por defecto, GSON imprime el JSON en un formato compacto, que hemos podido ver anteriormente:

1
2
{"firstName":"Max","lastName":"Tegmark","studentID":1254,"email":"[correo electrónico protegido]","courses":["Physics 8.01","Physics 8.012"],"financeType":"SUBSIDIZED"}
{"firstName":"Amy","lastName":"Winehouse","studentID":1328,"email":"[correo electrónico protegido]","courses":["Jazz","Blues"],"financeType":"SUBSIDIZED"}

No hay espacios en blanco entre los nombres de campo y sus valores, campos de objeto y objetos dentro de matrices. Además, no hay ni una sola nueva línea presente. Si se copia como una cadena, \n (nuevas líneas) estará presente, sin embargo, esta vista compacta es una molestia para leer.

Podemos activar la impresión bonita usando Gson, con bastante facilidad. Al instanciar Gson, en lugar de llamar al constructor vacío predeterminado, podemos usar el constructor GsonBuilder():

1
Gson gson = new GsonBuilder().setPrettyPrinting().create();

Ahora, podemos usar la instancia gson de la misma manera que lo hicimos antes:

1
2
3
Gson gson = new GsonBuilder().setPrettyPrinting().create();
String amyJson = gson.toJson(amy);
System.out.println(amyJson);

Sin embargo, esta vez, cuando se imprime, la cadena JSON tiene la impresión bonita activada:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
{
  "firstName": "Amy",
  "lastName": "Winehouse",
  "studentID": 1328,
  "email": "[correo electrónico protegido]",
  "courses": [
    "Jazz",
    "Blues"
  ],
  "financeType": "SUBSIDIZED"
}

Nombrar campos JSON con @SerializedName

La serialización se usa comúnmente para transferir datos entre servicios, en particular, a través de API REST. Cuando se trata de diferentes servicios, equipos o incluso idiomas que procesan los datos que proporcionamos, es posible que deseemos cambiar los nombres serializados de ciertos campos para cumplir con estándares más ampliamente aceptados, o con los estándares de un determinado servicio que\ estará tratando los datos que le proporcionemos.

Por ejemplo, podríamos proporcionar datos JSON desde un servicio de Java a un servicio de Python. Las convenciones de nomenclatura de Java siguen CamelCase, mientras que las convenciones de nomenclatura de Python siguen minúsculas_con_guiones bajos para no constantes y clases.

Sabiendo que proporcionaremos nuestros datos a un servicio o persona que podría querer usar diferentes convenciones, podemos cambiar los nombres serializados de nuestros campos para que no coincidan con los de nuestro POJO, a través de la anotación @SerializedName :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
public class Student {
    @SerializedName("first_name")
    private String firstName;
    @SerializedName("last_name")
    private String lastName;
    @SerializedName("student_id")
    private int studentID;
    @SerializedName("student_email")
    private String email;
    @SerializedName("student_courses")
    private List<String> courses;
    @SerializedName("student_finance_type")
    private FINANCE_TYPE financeType;

    // Getters, setters, constructor, toString()
}

Ahora, cuando se serialicen, estos nombres se utilizarán en lugar de nuestros nombres de campo:

1
2
String amyJson = gson.toJson(amy);
System.out.println(amyJson);

Lo que resulta en:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
{
  "first_name": "Amy",
  "last_name": "Winehouse",
  "student_id": 1328,
  "student_email": "[correo electrónico protegido]",
  "student_courses": [
    "Jazz",
    "Blues"
  ],
  "student_finance_type": "SUBSIDIZED"
}

Esto también funciona al revés: si recibimos JSON con first_name y nuestro Student POJO tiene first_name asignado a firstName, deserializaremos esto perfectamente:

1
2
3
4
String input = "{\"first_name\":\"Amy\",\"last_name\":\"Winehouse\",\"student_id\":1328,\"student_email\":\"[correo electrónico protegido]\",\"student_courses\":[\"Jazz\",\"Blues\"],\"student_finance_type\":\"SUBSIDIZED\"}";
Gson gson = new Gson();
Student amy = gson.fromJson(input, Student.class);
System.out.println(amy);

Esto resulta en:

1
Student{firstName='Amy', lastName='Winehouse', studentID=1328, email='[correo electrónico protegido]', courses=[Jazz, Blues], financeType=SUBSIDIZED}

Conclusión

En este tutorial, echamos un vistazo a cómo convertir un objeto Java en un objeto JSON con el método toJson() de Gson, y cómo convertir un objeto JSON en un objeto Java con el método toJson() de Gson. método fromJson()`.

También hemos explorado cómo habilitar la impresión bonita, así como cambiar los nombres serializados de los campos.