¿Para qué se usan @JsonTypeInfo y @JsonSubTypes en jackson?

3 minutos de lectura

Avatar de usuario de Harshit
mierda

¿Cuáles son los @JsonTypeInfo y @JsonSubTypes anotaciones utilizadas en Jackson?

public class Lion extends Animal {

private String name;

@JsonCreator
public Lion(@JsonProperty("name") String name) {
    this.name = name;
}

public String getName() {
    return name;
}

public String getSound() {
    return "Roar";
}

public String getType() {
    return "carnivorous";
}

public boolean isEndangered() {
    return true;
}

@Override
public String toString() {
    return "Lion [name=" + name + ", getName()=" + getName() + ", getSound()=" + getSound() + ", getType()=" + getType() + ", isEndangered()="
            + isEndangered() + "]";
}

}

========================================

public class Elephant extends Animal {

@JsonProperty
private String name;

@JsonCreator
public Elephant(@JsonProperty("name") String name) {
    this.name = name;
}

public String getName() {
    return name;
}

public String getSound() {
    return "trumpet";
}

public String getType() {
    return "herbivorous";
}

public boolean isEndangered() {
    return false;
}

@Override
public String toString() {
    return "Elephant [name=" + name + ", getName()=" + getName() + ", getSound()=" + getSound() + ", getType()=" + getType()
            + ", isEndangered()=" + isEndangered() + "]";
}
}

==============================================

@JsonTypeInfo (use = JsonTypeInfo.Id.CLASS, include = As.PROPERTY, property = "classNameExtenral")
@JsonSubTypes ({@Type (value = Lion.class, name = "lion"), @Type (value = Elephant.class, name = "elephant")})

public abstract class Animal {

@JsonProperty ("name")
String name;
@JsonProperty ("sound")
String sound;
@JsonProperty ("type")
String type;
@JsonProperty ("endangered")
boolean endangered;
}

public static void main(String[] args){
    Lion lion = new Lion("Simba");
    Elephant elephant = new Elephant("Manny");
    List<Animal> animals = new ArrayList<>();
    animals.add(lion);
    animals.add(elephant);
}

lo que entiendo es que además conserva el tipo concreto de objeto que se serializa junto con los datos reales.

lo que no me queda claro es cuál es la ventaja/ganancia real durante la deserialización.

No obtener ninguna documentación significativa aparte de los documentos de Java. ¿Alguien puede ayudar aquí o proporcionar algunos documentos sobre lo mismo?

  • Tal vez esta respuesta ayude: stackoverflow.com/a/31666888/751579

    – davidbak

    1 de agosto de 2017 a las 21:07

  • Ayuda .. gracias.

    – Harshit

    01/08/2017 a las 21:32

avatar de usuario de davidbak
davidbak

El propósito de estas anotaciones es apoyar polimorfismo sobre la deserialización. Al deserializar el código real que se está ejecutando sabrá el clase de lo que espera. Por ejemplo, el tipo de algún campo en el que se está deserializando. Pero si esa clase tiene subclases (es decir, subtipos), ¿cómo sabe el deserializador genérico de Jackson qué clase real es la cadena que se está deserializando? Tiene que crear una instancia de algún tipo concreto (la clase o una de sus subclases) y llenarla. La única forma en que puede saber cuál crear es si esa información es escrito en la serialización en primer lugar.

Como dice esta respuesta, hay tres formas de hacerlo: elige la que sea apropiada para su caso de uso. @JsonTypeInfo + @JsonSubtypes es una de esas formas: funciona muy bien cuando conoce, en tiempo de compilación, todos los posibles subtipos que podrían existir para la clase en cuestión.

  • ¿No tiene más sentido usar @JsonTypeInfo en las clases concretas individuales? Usarlo sobre la interfaz parece violar el principio de abrir y cerrar, supongo (ya que necesitamos modificar nuestra interfaz en cada nueva adición de una implementación concreta). Corrígeme si me falta algo aquí.

    – Harshit

    1 de agosto de 2017 a las 22:02

  • Una vez más, depende del caso de uso. Por ejemplo, tuve un caso de uso en el que, de hecho, podía usar @JsonSubtypes en un solo lugar y eso era preferible a etiquetar cada subtipo. Pero TBH, olvidé cuál era ese caso de uso ahora; Recuerdo que era un poco fuera de lo común. Pero tenía más que ver con problemas prácticos de implementación/lanzamiento que pura teoría OO. (Recuerde: cualquier “principio” como abrir-cerrar es solo una guía sólida… en algunos casos puede encontrar que violar dicho principio es un diseño correcto; solo asegúrese de saber realmente por qué).

    – davidbak

    01/08/2017 a las 23:10

  • Considere que tiene una jaula de clase que contiene un campo de tipo Animal. Cuando el objeto Cage se deserializa de JSON, Jackson descubre que debe crear un Animal, por lo que si Animal no está anotado con @JsonTypeInfo, Jackson no aplicará la compatibilidad con el polimorfismo, por lo que creará solo Animal (si es posible) y no su subtipo.

    – Konstantin Pelepelín

    4 sep 2017 a las 19:22

¿Ha sido útil esta solución?