Pourquoi lorsqu'un constructeur est annoté avec @JsonCreator, ses arguments doivent être annotés avec @JsonProperty?


109

Dans Jackson, lorsque vous annotez un constructeur avec @JsonCreator, vous devez annoter ses arguments avec @JsonProperty. Donc ce constructeur

public Point(double x, double y) {
    this.x = x;
    this.y = y;
}

devient ceci:

@JsonCreator
public Point(@JsonProperty("x") double x, @JsonProperty("y") double y) {
    this.x = x;
    this.y = y;
}

Je ne comprends pas pourquoi c'est nécessaire. Pouvez-vous expliquer?

Réponses:


113

Jackson doit savoir dans quel ordre passer les champs d'un objet JSON au constructeur. Il n'est pas possible d'accéder aux noms de paramètres en Java à l'aide de la réflexion - c'est pourquoi vous devez répéter ces informations dans les annotations.


9
Ce n'est pas valable pour Java8
MariuszS

12
@MariuszS C'est vrai, mais cet article explique comment se débarrasser des annotations superflues à l'aide du drapeau du compilateur Java8 et d'un module Jackson. J'ai testé l'approche et cela fonctionne.
quantum

Bien sûr, ça marche comme un charme :) docs.oracle.com/javase/tutorial/reflect/member/…
MariuszS

52

Les noms de paramètres ne sont normalement pas accessibles par le code Java au moment de l'exécution (car il est supprimé par le compilateur), donc si vous voulez cette fonctionnalité, vous devez soit utiliser la fonctionnalité intégrée de Java 8, soit utiliser une bibliothèque telle que ParaNamer pour y accéder. à lui.

Donc, pour ne pas avoir à utiliser d'annotations pour les arguments du constructeur lors de l'utilisation de Jackson, vous pouvez utiliser l'un de ces 2 modules Jackson:

noms de paramètres de module jackson

Ce module vous permet d'obtenir des arguments de constructeur sans annotations lors de l'utilisation de Java 8 . Pour l'utiliser, vous devez d'abord enregistrer le module:

ObjectMapper mapper = new ObjectMapper();
mapper.registerModule(new ParameterNamesModule());

Ensuite, compilez votre code à l'aide de l'indicateur -parameters:

javac -parameters ...

Lien: https://github.com/FasterXML/jackson-modules-java8/tree/master/parameter-names

jackson-module-paranamer

Cet autre vous demande simplement d'enregistrer le module ou de configurer une introspection d'annotation (mais pas les deux comme indiqué par les commentaires). Il vous permet d'utiliser des arguments de constructeur sans annotations sur les versions de Java antérieures à la 1.8 .

ObjectMapper mapper = new ObjectMapper();
// either via module
mapper.registerModule(new ParanamerModule());
// or by directly assigning annotation introspector (but not both!)
mapper.setAnnotationIntrospector(new ParanamerOnJacksonAnnotationIntrospector());

Lien: https://github.com/FasterXML/jackson-modules-base/tree/master/paranamer


28

Il est possible d'éviter les annotations de constructeur avec jdk8 où le compilateur introduira éventuellement des métadonnées avec les noms des paramètres du constructeur. Ensuite, avec le module jackson-module-parameter-names, Jackson peut utiliser ce constructeur. Vous pouvez voir un exemple au post Jackson sans annotations


obsolète et déplacé vers jackson-modules-java8 / parameter-names
naXa


6

On peut simplement utiliser l'annotation java.bean.ConstructorProperties - elle est beaucoup moins verbeuse et Jackson l'accepte également. Par exemple :

  import java.beans.ConstructorProperties;

  @ConstructorProperties({"answer","closed","language","interface","operation"})
  public DialogueOutput(String answer, boolean closed, String language, String anInterface, String operation) {
    this.answer = answer;
    this.closed = closed;
    this.language = language;
    this.anInterface = anInterface;
    this.operation = operation;
  }

4

Lorsque je comprends cela correctement, vous remplacez le constructeur par défaut par un constructeur paramétré et devez donc décrire les clés JSON qui sont utilisées pour appeler le constructeur avec.


3

Comme précisé dans la documentation de l' annotation , l'annotation indique que le nom de l'argument est utilisé comme nom de propriété sans aucune modification, mais il peut être spécifié sur une valeur non vide pour spécifier un nom différent:


0

Il suffit de le découvrir et d'obtenir une réponse quelque part. vous pouvez utiliser l'annotation ci-dessous depuis 2.7.0

@JsonAutoDetect(fieldVisibility = JsonAutoDetect.Visibility.ANY)
public class Point {
    final private double x;
    final private double y;

    @ConstructorProperties({"x", "y"})
    public Point(double x, double y) {
        this.x = x;
        this.y = y;
    }
}
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.