Quand la propriété @JsonProperty est-elle utilisée et à quoi sert-elle?

183

Ce haricot 'State':

public class State {

    private boolean isSet;

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

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

}

est envoyé sur le fil en utilisant le rappel ajax 'success':

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

L'annotation @JsonProperty est-elle requise ici? Quel est l'avantage de l'utiliser? Je pense que je peux supprimer cette annotation sans provoquer d'effets secondaires.

En lisant cette annotion sur https://github.com/FasterXML/jackson-annotations/wiki/Jackson-Annotations Je ne sais pas quand cela doit être utilisé?

ciel bleu
la source

Réponses:

238

Voici un bon exemple. Je l'utilise pour renommer la variable car le JSON provient d'un.Net environnement où les propriétés commencent par une lettre majuscule.

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

Cela analyse correctement vers / depuis le JSON:

"Parameter":{
  "Name":"Parameter-Name",
  "Value":"Parameter-Value"
}
VieuxCurmudgeon
la source
1
Les variables membres String peuvent-elles ne pas être renommées dans leur casse correcte, donc public String name; devient public String Name; ?
blue-sky
14
Oui, ils le peuvent, mais dans un environnement Java qui les rend non conformes aux normes de codage. C'est plus mon pédantisme qu'un vrai problème de codage, mais c'est un bon exemple simple d'utilisation réelle de l' @JsonPropertyannotation.
OldCurmudgeon
Cette annotation peut-elle être utilisée pour le membre de type Double? Je me demande simplement si le type doit être Stringou n'importe quel type pris en charge par JSON? Pourrait-il être n'importe quel type? @OldCurmudgeon
Dreamer
3
@Dreamer Oui. Le type n'est pas pertinent. Cela n'affecte que le nom .
OldCurmudgeon
1
@Pavan - Cela n'aura rien à voir avec la dénomination. Je suppose que vous devriez examiner vos setters.
OldCurmudgeon
44

Je pense que OldCurmudgeon et StaxMan sont tous les deux corrects, mais voici une réponse en une phrase avec un exemple simple pour vous.

@JsonProperty (nom), indique à Jackson ObjectMapper de mapper le nom de la propriété JSON avec le nom du champ Java annoté.

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

//where it gets mapped 
public static class Car {
  @JsonProperty("Type")
  public String type;
 }
grepit
la source
Le nom de la classe doit-il être identique à l'élément racine de JSON? Cela ne fonctionne pas pour moi.
Pavan
39

bien pour ce que ça vaut maintenant ... JsonProperty est ÉGALEMENT utilisé pour spécifier les méthodes getter et setter pour la variable en dehors de la sérialisation et de la désérialisation habituelles. Par exemple, supposons que vous ayez une charge utile comme celle-ci:

{
  "check": true
}

et une classe 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;
  }
}

Dans ce cas, l'annotation JsonProperty est alors nécessaire. Cependant si vous avez également une méthode dans la classe

public class Check {

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

  public Boolean getCheck() {
     return check;
  }
}

Jetez aussi un œil à cette documentation: http://fasterxml.github.io/jackson-annotations/javadoc/2.3.0/com/fasterxml/jackson/annotation/JsonProperty.html

Richeek
la source
15

Sans annotations, le nom de la propriété inférée (pour correspondre à partir de JSON) serait "set", et non - comme cela semble être l'intention - "isSet". En effet, selon la spécification Java Beans, les méthodes de la forme «isXxx» et «setXxx» signifient qu'il existe une propriété logique «xxx» à gérer.

StaxMan
la source
1
Celui-ci est la bonne réponse pour le cas spécifique donné dans la question
Andrew Spencer
6

Comme vous le savez, il s'agit de sérialiser et de désaliniser un objet. Supposons qu'il y ait un objet:

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

La sérialisation de cet objet est:

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

Le nom de la variable est directement utilisé pour sérialiser les données. Si vous êtes sur le point de supprimer l'API système de l'implémentation système, dans certains cas, vous devez renommer la variable dans la sérialisation / désérialisation. @JsonProperty est une méta-données pour indiquer au sérialiseur comment mettre en série un objet. Il sert à:

  • Nom de variable
  • accès (LIRE, ÉCRIRE)
  • valeur par défaut
  • requis / facultatif

de l'exemple:

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
la source
6

L'ajout de JsonProperty garantit également la sécurité au cas où quelqu'un déciderait de changer l'un des noms de propriété sans se rendre compte que la classe en question sera sérialisée en un objet Json. S'ils modifient le nom de la propriété, JsonProperty garantit qu'il sera utilisé dans l'objet Json, et non dans le nom de la propriété.

arush436
la source
3

En plus d'autres réponses, l' @JsonPropertyannotation est vraiment importante si vous utilisez l' @JsonCreatorannotation dans des classes qui n'ont pas de constructeur sans argument.

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);
    }
}

Dans cet exemple, le seul constructeur est marqué comme @JsonCreator, par conséquent Jackson utilisera ce constructeur pour créer l'instance. Mais la sortie est comme:

Sérialisé: {"stringValue": "ABCD", "myEnum": "FIRST"}

Exception dans le thread "main" com.fasterxml.jackson.databind.exc.InvalidFormatException: impossible de construire une instance de ClassToSerialize $ MyEnum à partir de la valeur de chaîne "stringValue": la valeur n'est pas l'un des noms d'instance Enum déclarés: [FIRST, SECOND, THIRD]

Mais après l'ajout de l' @JsonPropertyannotation dans le constructeur:

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

La désérialisation est réussie:

Sérialisé: {"myEnum": "FIRST", "stringValue": "ABCD"}

StringValue: ABCD

MyEnum: PREMIER

DVarga
la source
2

En plus de toutes les réponses ci-dessus, n'oubliez pas la partie de la documentation qui dit

Annotation de marqueur qui peut être utilisée pour définir une méthode non statique en tant que "setter" ou "getter" pour une propriété logique (selon sa signature), ou champ d'objet non statique à utiliser (sérialisé, désérialisé) comme logique propriété.

Si vous avez une non-staticméthode dans votre classe qui n'est pas conventionnelle, getter or settervous pouvez la faire agir comme une getter and setteren utilisant l'annotation dessus. Voir l'exemple ci-dessous

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; 
    }
}

Lorsque l'objet ci-dessus est sérialisé, la réponse contiendra

  • nom d'utilisateur de getUsername()
  • identifiant de getId()
  • idAndUsername de getIdAndUsername*

Puisque la méthode getIdAndUsernamecommence par, getelle est traitée comme un getter normal, pourquoi vous pouvez l'annoter avec@JsonIgnore .

Si vous avez remarqué que le concatenateIdAndUsernamen'est pas retourné et que c'est parce que son nom ne commence pas par getet si vous souhaitez que le résultat de cette méthode soit inclus dans la réponse, vous pouvez l'utiliser @JsonProperty("...")et il sera traité comme normal getter/settercomme mentionné dans la documentation en surbrillance ci-dessus .

Raf
la source
0

De JsonProperty javadoc,

Définit le nom de la propriété logique, c'est-à-dire le nom du champ d'objet JSON à utiliser pour la propriété. Si la valeur est vide String (qui est la valeur par défaut), essaiera d'utiliser le nom du champ annoté.

sc30
la source