JsonIgnore, JsonProperty y JsonAlias

Si queremos modificar la forma en la que se serializa a JSON una entidad, tenemos las anotaciones JsonIgnore, JsonProperty y JsonAlias para influir en la forma en la que Jackson serializa nuestra entidad, para ocultar campos o renombrarlos.

Ignorar campos con JsonIgnore

Cuando dejamos que Jackson serialice una clase o un registro a JSON o XML para devolverlo en nuestra API Quarkus, nos encontraremos en ocasiones que hay información que preferiríamos no hacer visible. Por ejemplo, puede que querramos ocultar el identificador, o los campos de fecha de creación y modificación.

Con la anotación @JsonIgnore (importable desde com.fasterxml.jackson.annotation.JsonIgnore), podemos pedirle a Jackson que excluya esa propiedad cuando esté generando el JSON o el XML correspondiente. En el siguiente ejemplo, inicialmente la API nos devuelve todas las propiedades de un género:

{
  "id": 2,
  "name": "Poesía",
  "createdAt": "2023-07-23T12:04:37",
  "updatedAt": "2023-07-23T12:07:28"
}

Sin embargo, si le añadimos esta anotación a los campos createdAt y updatedAt:

@CreationTimestamp
@JsonIgnore
private LocalDateTime createdAt;

@UpdateTimestamp
@JsonIgnore
private LocalDateTime updatedAt;

La próxima vez que visitemos ese endpoint ya no se incluirán en la respuesta:

{
  "id": 2,
  "name": "Poesía"
}

Renombrar campos con JsonProperty

Por defecto, Jackson usará el nombre del campo de Java como fuente para la clave del campo JSON que se usa al pasar una clase a JSON o al convertir de JSON a instancia de clase. Con la anotación JsonProperty, importable desde com.fasterxml.jackson.annotation.JsonProperty, podemos cambiar el nombre dado. Por ejemplo, si anotamos un campo name del siguiente modo:

@JsonProperty("genreName")
private String name;

Ahora el JSON tendrá el siguiente aspecto:

{
  "id": 2,
  "genreName": "Poesía"
}

No solo eso, sino que también cambiará la forma de declarar el campo cuando queramos insertar o modificar elementos. Por lo tanto, lo siguiente ya no será válido:

# POST /genres
{
  "name": "Psicología"
}

Ahora tendrá que ser indicado del siguiente modo:

# POST /genres
{
  "genreName": "Psicología"
}

Permitir darle varios nombres a una key con JsonAlias

Si no queremos ese comportamiento colateral que nos provoca JsonProperty en los payloads de entrada, podemos usar la anotación JsonAlias. Esta anotación es importable desde com.fasterxml.jackson.annotation.JsonAlias y recibe como parámetro un array con todos los nombres de key que mapearán contra este campo cuando se deserialicen objetos JSON. Eso significa que cuando le pasemos a la API un payload JSON, será válido cualquiera de los nombres dados a la hora de elegir el campo del JSON que tiene que almacenarse en esa key.

Por lo tanto, si lo combinamos del siguiente modo:

@JsonProperty("genreName")
@JsonAlias({ "genreName", "name" })
private String name;

Ahora tanto genreName como name serán nombres válidos de clave que se pueden proporcionar en el JSON. El siguiente objeto es válido:

{
  "genreName": "Criminología"
}

Pero el siguiente objeto también es válido, porque el alias establece que puede llamarse así:

{
  "name": "Sociología"
}

A tener en cuenta que esto solo afecta a las entradas de datos. Para las salidas de datos tiene preferencia el nombre real del campo o el que se haya declarado mediante JsonProperty:

# POST /genres
{
  "name": "Humanismo"
}

# "HTTP 200 OK"
{
  "id": 46,
  "genreName": "Humanismo"
}

Campos virtuales

Un último apunte: para Jackson, cualquier getter será considerado parte de algo a serializar salvo que se excluya con JsonIgnore. Podemos aprovechar esto para fabricar campos con keys virtuales que realmente no procedan de base de datos. En el siguiente ejemplo, le agregamos a la clase Genre un getter llamado getLongitud() que calcula el ancho del nombre:

public class Genre {
  private String name;

  public int getLongitud() {
    return name.length;
  }

  public String getName() {
    return name;
  }

  public void setName(String name) {
    this.name = name;
  }
}

Bueno, pues al haber hecho esto, implícitamente y salvo que lo cambiemos con la anotación JsonIgnore, ahora se incluirá el nuevo campo en las respuestas:

{
  "id": 5,
  "name": "Parapsicología",
  "longitud": 14
}
Lista de reproducción
  1. 1
    Configurar una base de datos
    7 minutos
  2. 2
    Crear una entidad y un repositorio
    12 minutos
  3. 3
    Active Record con PanacheEntity
    4 minutos
  4. 4
    Modificar y borrar registros
    12 minutos
  5. 5
    Filtros y ordenación
    12 minutos
  6. 6
    Paginación de resultados
    13 minutos
  7. 7
    Aplicar filtros dinámicos
    12 minutos
  8. 8
    JsonIgnore, JsonProperty y JsonAlias
    6 minutos