¿Cuándo se usa la propiedad @JsonProperty y para qué se usa?

183

Este 'Estado' de frijol:

public class State {

    private boolean isSet;

    @JsonProperty("isSet")
    public boolean isSet() {
        return isSet;
    }

    @JsonProperty("isSet")
    public void setSet(boolean isSet) {
        this.isSet = isSet;
    }

}

se envía por cable utilizando la devolución de llamada de 'éxito' ajax

        success : function(response) {  
            if(response.State.isSet){   
                alert('success called successfully)
            }

¿Se requiere la anotación @JsonProperty aquí? ¿Cuál es la ventaja de usarlo? Creo que puedo eliminar esta anotación sin causar ningún efecto secundario.

Leyendo sobre esta anotación en https://github.com/FasterXML/jackson-annotations/wiki/Jackson-Annotations ¿No sé cuándo es necesario usar esto?

cielo azul
fuente

Respuestas:

238

Aquí hay un buen ejemplo. Lo uso para cambiar el nombre de la variable porque el JSON proviene de un .Netentorno donde las propiedades comienzan con una letra mayúscula.

public class Parameter {
  @JsonProperty("Name")
  public String name;
  @JsonProperty("Value")
  public String value; 
}

Esto analiza correctamente a / desde el JSON:

"Parameter":{
  "Name":"Parameter-Name",
  "Value":"Parameter-Value"
}
OldCurmudgeon
fuente
1
¿No se puede cambiar el nombre de las variables miembro de la cadena a su caso correcto, por lo que el nombre público de la cadena; se convierte en Nombre de cadena público; ?
cielo azul
14
Sí pueden, pero en un entorno Java que los hace no coincidir con los estándares de codificación. Se trata más de mi pedantería que de un problema de codificación real, pero es un buen pero simple ejemplo del uso real de la @JsonPropertyanotación.
OldCurmudgeon
¿Se puede usar esta anotación para el miembro de tipo Double? Me pregunto si el tipo tiene que ser Stringo cualquier tipo compatible con JSON. ¿Podría ser de cualquier tipo? @OldCurmudgeon
Dreamer
3
@Dreamer Sí. El tipo es irrelevante. Esto solo afecta el nombre .
OldCurmudgeon
1
@Pavan: eso no tendrá nada que ver con el nombramiento. Me supongo que debe examinar sus emisores.
OldCurmudgeon
44

Creo que OldCurmudgeon y StaxMan son correctos, pero aquí hay una respuesta de oración con un ejemplo simple para ti.

@JsonProperty (nombre), le dice a Jackson ObjectMapper que asigne el nombre de la propiedad JSON al nombre del campo Java anotado.

//example of json that is submitted 
"Car":{
  "Type":"Ferrari",
}

//where it gets mapped 
public static class Car {
  @JsonProperty("Type")
  public String type;
 }
grepit
fuente
¿El nombre de la clase debe ser el mismo que el elemento raíz de JSON? Esto no está funcionando para mí.
Pavan
39

bien por lo que vale ahora ... JsonProperty TAMBIÉN se usa para especificar métodos getter y setter para la variable, aparte de la serialización y deserialización habituales. Por ejemplo, suponga que tiene una carga útil como esta:

{
  "check": true
}

y una clase Deserializer:

public class Check {

  @JsonProperty("check")    // It is needed else Jackson will look got getCheck method and will fail
  private Boolean check;

  public Boolean isCheck() {
     return check;
  }
}

Entonces, en este caso, se necesita la anotación JsonProperty. Sin embargo, si también tienes un método en la clase

public class Check {

  //@JsonProperty("check")    Not needed anymore
  private Boolean check;

  public Boolean getCheck() {
     return check;
  }
}

Eche un vistazo a esta documentación también: http://fasterxml.github.io/jackson-annotations/javadoc/2.3.0/com/fasterxml/jackson/annotation/JsonProperty.html

Richeek
fuente
15

Sin anotaciones, el nombre de propiedad inferido (para que coincida con JSON) se "establecería" y no, como parece ser la intención, "isSet". Esto se debe a que, según la especificación de Java Beans, los métodos de forma "isXxx" y "setXxx" significan que hay una propiedad lógica "xxx" para administrar.

StaxMan
fuente
1
Esta es la respuesta correcta para el caso específico dado en la pregunta
Andrew Spencer,
6

Como saben, se trata de serializar y desalinizar un objeto. Supongamos que hay un objeto:

public class Parameter {
  public String _name;
  public String _value; 
}

La serialización de este objeto es:

{
  "_name": "...",
  "_value": "..."
}

El nombre de la variable se usa directamente para serializar datos. Si está a punto de eliminar la API del sistema de la implementación del sistema, en algunos casos, debe cambiar el nombre de la variable en serialización / deserialización. @JsonProperty es un metadato para indicarle al serializador cómo serializar un objeto. Es usado para:

  • nombre de la variable
  • acceso (LEER, ESCRIBIR)
  • valor por defecto
  • requerido / opcional

de ejemplo:

public class Parameter {
  @JsonProperty(
        value="Name",
        required=true,
        defaultValue="No name",
        access= Access.READ_WRITE)
  public String _name;
  @JsonProperty(
        value="Value",
        required=true,
        defaultValue="Empty",
        access= Access.READ_WRITE)
  public String _value; 
}
Mostafa
fuente
6

Agregar JsonProperty también garantiza la seguridad en caso de que alguien decida que desea cambiar uno de los nombres de propiedad sin darse cuenta de que la clase en cuestión se serializará en un objeto Json. Si cambian el nombre de la propiedad, JsonProperty asegura que se utilizará en el objeto Json y no en el nombre de la propiedad.

arush436
fuente
3

Además de otras respuestas, la @JsonPropertyanotación es realmente importante si usa la @JsonCreatoranotación en clases que no tienen un constructor sin argumentos.

public class ClassToSerialize {

    public enum MyEnum {
        FIRST,SECOND,THIRD
    }

    public String stringValue = "ABCD";
    public MyEnum myEnum;


    @JsonCreator
    public ClassToSerialize(MyEnum myEnum) {
        this.myEnum = myEnum;
    }

    public static void main(String[] args) throws IOException {
        ObjectMapper mapper = new ObjectMapper();

        ClassToSerialize classToSerialize = new ClassToSerialize(MyEnum.FIRST);
        String jsonString = mapper.writeValueAsString(classToSerialize);
        System.out.println(jsonString);
        ClassToSerialize deserialized = mapper.readValue(jsonString, ClassToSerialize.class);
        System.out.println("StringValue: " + deserialized.stringValue);
        System.out.println("MyEnum: " + deserialized.myEnum);
    }
}

En este ejemplo, el único constructor está marcado como @JsonCreator, por lo tanto, Jackson usará este constructor para crear la instancia. Pero la salida es como:

Serializado: {"stringValue": "ABCD", "myEnum": "FIRST"}

Excepción en el subproceso "main" com.fasterxml.jackson.databind.exc.InvalidFormatException: No se puede construir la instancia de ClassToSerialize $ MyEnum a partir del valor de cadena 'stringValue': valor no uno de los nombres de instancia de Enum declarados: [FIRST, SECOND, THIRD]

Pero después de la adición de la @JsonPropertyanotación en el constructor:

@JsonCreator
public ClassToSerialize(@JsonProperty("myEnum") MyEnum myEnum) {
    this.myEnum = myEnum;
}

La deserialización es exitosa:

Serializado: {"myEnum": "FIRST", "stringValue": "ABCD"}

StringValue: ABCD

MyEnum: PRIMERO

DVarga
fuente
2

Además de todas las respuestas anteriores, no olvide la parte de la documentación que dice

Anotación de marcador que se puede usar para definir un método no estático como un "setter" o "getter" para una propiedad lógica (dependiendo de su firma), o un campo de objeto no estático para ser usado (serializado, deserializado) como lógico propiedad.

Si tiene un non-staticmétodo en su clase que no es convencional getter or setter, puede hacer que actúe como tal getter and setterutilizando la anotación en él. Vea el ejemplo a continuación.

public class Testing {
    private Integer id;
    private String username;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getIdAndUsername() {
        return id + "." + username; 
    }

    public String concatenateIdAndUsername() {
        return id + "." + username; 
    }
}

Cuando el objeto anterior se serializa, la respuesta contendrá

  • nombre de usuario de getUsername()
  • identificación de getId()
  • idAndUsername desde getIdAndUsername*

Dado que el método getIdAndUsernamecomienza con, getentonces se trata como un captador normal, por lo tanto, ¿por qué podría anotar tal @JsonIgnore?

Si ha notado concatenateIdAndUsernameque no se devuelve y eso se debe a que su nombre no comienza gety si desea que el resultado de ese método se incluya en la respuesta, puede usarlo @JsonProperty("...")y se trataría de la manera normal getter/settercomo se menciona en la documentación resaltada anteriormente .

Raf
fuente
0

De JsonProperty javadoc,

Define el nombre de la propiedad lógica, es decir, el nombre del campo del objeto JSON que se utilizará para la propiedad. Si el valor es una cadena vacía (que es la predeterminada), intentará usar el nombre del campo que está anotado.

sc30
fuente